Merge changes I21f07545,I73c39cbe,I47b1639c,I4a6268d7,I06be9898, ... into nyc-dev

* changes:
  vulkan: remove unused loader.{cpp.h}
  vulkan: use driver::GetData everywhere
  vulkan: move all _Bottom functions
  vulkan: add swapchain.h
  vulkan: add layers_extensions.h
  vulkan: rework CreateInstance_Bottom and related ones
  vulkan: rework EnumerateDeviceExtensionProperties_Bottom
  vulkan: rework {Create,Destroy}Device_Bottom
  vulkan: move AllocateCommandBuffers_Bottom
  vulkan: move GetDeviceQueue_Bottom
  vulkan: rework DriverDispatchTable
  vulkan: rework driver::Get*ProcAddr
  vulkan: add VK_ANDROID_native_buffer to vulkan.api
  vulkan: move driver::GetDefaultAllocator
  vulkan: move driver::OpenHAL
  vulkan: move driver::Debuggable
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 980722d..7aa19e7 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -43,6 +43,7 @@
 
 // VK_USE_PLATFORM_ANDROID_KHR
 @internal class ANativeWindow {}
+@internal type void* buffer_handle_t
 
 // VK_USE_PLATFORM_WIN32_KHR
 @internal type void* HINSTANCE
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 10565ab..ae690a3 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -75,6 +75,9 @@
 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION     5
 @extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME             "VK_KHR_win32_surface"
 
+@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION     5
+@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME             "VK_ANDROID_native_buffer"
+
 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       1
 @extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME               "VK_EXT_debug_report"
 
@@ -646,6 +649,9 @@
     //@extension("VK_KHR_win32_surface")
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR             = 1000009000,
 
+    //@extension("VK_ANDROID_native_buffer")
+    VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID                     = 1000010000,
+
     //@extension("VK_EXT_debug_report")
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT              = 1000011000,
 }
@@ -2591,6 +2597,16 @@
     platform.HWND                               hwnd
 }
 
+@extension("VK_ANDROID_native_buffer")
+class VkNativeBufferANDROID {
+    VkStructureType                             sType
+    const void*                                 pNext
+    platform.buffer_handle_t                    handle
+    int                                         stride
+    int                                         format
+    int                                         usage
+}
+
 @extension("VK_EXT_debug_report")
 class VkDebugReportCallbackCreateInfoEXT {
     VkStructureType                             sType
@@ -5134,6 +5150,35 @@
     return ?
 }
 
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkGetSwapchainGrallocUsageANDROID(
+        VkDevice                                device,
+        VkFormat                                format,
+        VkImageUsageFlags                       imageUsage,
+        int*                                    grallocUsage) {
+    return ?
+}
+
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkAcquireImageANDROID(
+        VkDevice                                device,
+        VkImage                                 image,
+        int                                     nativeFenceFd,
+        VkSemaphore                             semaphore,
+        VkFence                                 fence) {
+    return ?
+}
+
+@extension("VK_ANDROID_native_buffer")
+cmd VkResult vkQueueSignalReleaseImageANDROID(
+        VkQueue                                 queue,
+        u32                                     waitSemaphoreCount,
+        const VkSemaphore*                      pWaitSemaphores,
+        VkImage                                 image,
+        int*                                    pNativeFenceFd) {
+    return ?
+}
+
 @extension("VK_EXT_debug_report")
 @external type void* PFN_vkDebugReportCallbackEXT
 @extension("VK_EXT_debug_report")
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index e60d74c..0979471 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -42,9 +42,9 @@
 	api.cpp \
 	api_gen.cpp \
 	debug_report.cpp \
-	dispatch_gen.cpp \
+	driver.cpp \
+	driver_gen.cpp \
 	layers_extensions.cpp \
-	loader.cpp \
 	swapchain.cpp \
 	vulkan_loader_data.cpp
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 549886f..e463f02 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -33,7 +33,7 @@
 #include <vulkan/vk_layer_interface.h>
 #include "api.h"
 #include "driver.h"
-#include "loader.h"
+#include "layers_extensions.h"
 
 namespace vulkan {
 namespace api {
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 7ebe983..afe0d84 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -21,6 +21,8 @@
 {{Macro "DefineGlobals" $}}
 {{$ | Macro "api_gen.h"   | Format (Global "clang-format") | Write "api_gen.h"  }}
 {{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}}
+{{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}}
+{{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}}
 
 {{/*
 -------------------------------------------------------------------------------
@@ -44,7 +46,7 @@
   // clang-format off
   {{range $f := AllCommands $}}
     {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
-      {{Macro "C++.DeclareDispatchTableEntry" $f}};
+      {{Macro "C++.DeclareTableEntry" $f}};
     {{end}}
   {{end}}
   // clang-format on
@@ -54,7 +56,7 @@
   // clang-format off
   {{range $f := AllCommands $}}
     {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
-      {{Macro "C++.DeclareDispatchTableEntry" $f}};
+      {{Macro "C++.DeclareTableEntry" $f}};
     {{end}}
   {{end}}
   // clang-format on
@@ -89,7 +91,9 @@
 namespace vulkan {«
 namespace api {«

-{{Macro "C++.DefineInitProcMacros" "dispatch"}}
+{{Macro "C++.DefineInitProcMacro" "dispatch"}}

+{{Macro "api.C++.DefineInitProcExtMacro"}}

 bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) {
     auto& data = GetData(instance);
@@ -147,11 +151,173 @@
 
 
 {{/*
+-------------------------------------------------------------------------------
+  driver_gen.h
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.h"}}
+{{Macro "Copyright"}}

+// WARNING: This file is generated. See ../README.md for instructions.

+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H

+#include <vulkan/vulkan.h>
+#include <vulkan/vk_android_native_buffer.h>

+namespace vulkan {«
+namespace driver {«

+{{Macro "driver.C++.DefineProcHookType"}}

+struct InstanceDriverTable {
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
+      {{Macro "C++.DeclareTableEntry" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+struct DeviceDriverTable {
+  // clang-format off
+  {{range $f := AllCommands $}}
+    {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
+      {{Macro "C++.DeclareTableEntry" $f}};
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);

+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);

+»} // namespace driver
+»} // namespace vulkan

+#endif // LIBVULKAN_DRIVER_TABLE_H
+¶{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  driver_gen.cpp
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver_gen.cpp"}}
+{{Macro "Copyright"}}

+// WARNING: This file is generated. See ../README.md for instructions.

+#include <string.h>
+#include <algorithm>
+#include <log/log.h>

+#include "driver.h"

+namespace vulkan {«
+namespace driver {«

+namespace {«

+// clang-format off

+{{range $f := AllCommands $}}
+  {{Macro "driver.C++.DefineProcHookStubs" $f}}
+{{end}}
+// clang-format on

+const ProcHook g_proc_hooks[] = {
+  // clang-format off
+  {{range $f := SortBy (AllCommands $) "FunctionName"}}
+    {{if (Macro "driver.IsIntercepted" $f)}}
+      {{     if (Macro "IsGloballyDispatched" $f)}}
+        {{Macro "driver.C++.DefineGlobalProcHook" $f}}
+      {{else if (Macro "IsInstanceDispatched" $f)}}
+        {{Macro "driver.C++.DefineInstanceProcHook" $f}}
+      {{else if (Macro "IsDeviceDispatched" $f)}}
+        {{Macro "driver.C++.DefineDeviceProcHook" $f}}
+      {{end}}
+    {{end}}
+  {{end}}
+  // clang-format on
+};

+»} // anonymous

+const ProcHook* GetProcHook(const char* name) {
+    const auto& begin = g_proc_hooks;
+    const auto& end = g_proc_hooks +
+      sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+    const auto hook = std::lower_bound(begin, end, name,
+        [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+    return (hook <  end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}

+ProcHook::Extension GetProcHookExtension(const char* name) {
+  {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+  // clang-format off
+  {{range $e := $exts}}
+    if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}};
+  {{end}}
+  // clang-format on
+  return ProcHook::EXTENSION_UNKNOWN;
+}

+{{Macro "C++.DefineInitProcMacro" "driver"}}

+{{Macro "driver.C++.DefineInitProcExtMacro"}}

+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc)
+{
+    auto& data = GetData(instance);
+    bool success = true;
+    ¶
+    // clang-format off
+    {{range $f := AllCommands $}}
+      {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
+        {{Macro "C++.InitProc" $f}}
+      {{end}}
+    {{end}}
+    // clang-format on
+    ¶
+    return success;
+}

+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc)
+{
+    auto& data = GetData(dev);
+    bool success = true;
+    ¶
+    // clang-format off
+    {{range $f := AllCommands $}}
+      {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
+        {{Macro "C++.InitProc" $f}}
+      {{end}}
+    {{end}}
+    // clang-format on
+    ¶
+    return success;
+}

+»} // namespace driver
+»} // namespace vulkan

+// clang-format on
+¶{{end}}
+
+
+{{/*
 ------------------------------------------------------------------------------
-  Emits a declaration of a dispatch table entry.
+  Emits a declaration of a dispatch/driver table entry.
 ------------------------------------------------------------------------------
 */}}
-{{define "C++.DeclareDispatchTableEntry"}}
+{{define "C++.DeclareTableEntry"}}
   {{AssertType $ "Function"}}
 
   {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}}
@@ -160,10 +326,10 @@
 
 {{/*
 -------------------------------------------------------------------------------
-  Emits macros to help initialize dispatch tables.
+  Emits INIT_PROC macro.
 -------------------------------------------------------------------------------
 */}}
-{{define "C++.DefineInitProcMacros"}}
+{{define "C++.DefineInitProcMacro"}}
   #define UNLIKELY(expr) __builtin_expect((expr), 0)

   #define INIT_PROC(obj, proc) do {                             \
@@ -174,11 +340,6 @@
           success = false;                                      \
       }                                                         \
   } while(0)
-  ¶
-  // TODO do we want to point to a stub or nullptr when ext is not enabled?
-  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
-      INIT_PROC(obj, proc);                                     \
-  } while(0)
 {{end}}
 
 
@@ -262,6 +423,19 @@
 
 
 {{/*
+-------------------------------------------------------------------------------
+  Emits INIT_PROC_EXT macro for vulkan::api.
+-------------------------------------------------------------------------------
+*/}}
+{{define "api.C++.DefineInitProcExtMacro"}}
+  // TODO do we want to point to a stub or nullptr when ext is not enabled?
+  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
+      INIT_PROC(obj, proc);                                     \
+  } while(0)
+{{end}}
+
+
+{{/*
 ------------------------------------------------------------------------------
   Emits code for vkGetInstanceProcAddr for function interception.
 ------------------------------------------------------------------------------
@@ -386,6 +560,348 @@
 
 
 {{/*
+------------------------------------------------------------------------------
+  Emits a list of extensions intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.InterceptedExtensions"}}
+VK_ANDROID_native_buffer
+VK_EXT_debug_report
+VK_KHR_android_surface
+VK_KHR_surface
+VK_KHR_swapchain
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if an extension is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsExtensionIntercepted"}}
+  {{$ext_name := index $.Arguments 0}}
+  {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+
+  {{range $f := $filters}}
+    {{if eq $ext_name $f}}true{{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a function is intercepted by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsIntercepted"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{/* Create functions of dispatchable objects */}}
+    {{     if eq $.Name "vkCreateInstance"}}true
+    {{else if eq $.Name "vkCreateDevice"}}true
+    {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+    {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+    {{/* Destroy functions of dispatchable objects */}}
+    {{else if eq $.Name "vkDestroyInstance"}}true
+    {{else if eq $.Name "vkDestroyDevice"}}true
+
+    {{/* Enumeration of extensions */}}
+    {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true
+    {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
+
+    {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+    {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+    {{end}}
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{Macro "driver.IsExtensionIntercepted" $ext}}
+    {{end}}
+
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a function needs ProcHook stubs.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.NeedProcHookStubs"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "driver.IsIntercepted" $)}}
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}}
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of struct ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookType"}}
+  struct ProcHook {
+      enum Type {
+        GLOBAL,
+        INSTANCE,
+        DEVICE,
+      };
+
+      enum Extension {
+        {{$exts := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
+        {{range $e := $exts}}
+          {{TrimPrefix "VK_" $e}},
+        {{end}}
+        ¶
+        EXTENSION_CORE, // valid bit
+        EXTENSION_COUNT,
+        EXTENSION_UNKNOWN,
+      };
+      ¶
+      const char* name;
+      Type type;
+      Extension extension;
+      ¶
+      PFN_vkVoidFunction proc;
+      PFN_vkVoidFunction disabled_proc; // nullptr for global hooks
+      PFN_vkVoidFunction checked_proc;  // nullptr for global/instance hooks
+  };
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits INIT_PROC_EXT macro for vulkan::driver.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineInitProcExtMacro"}}
+  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
+      if (data.hal_extensions[ProcHook::ext])           \
+        INIT_PROC(obj, proc);                                   \
+  } while(0)
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definitions of stub functions for ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineProcHookStubs"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "driver.NeedProcHookStubs" $)}}
+    {{$ext := GetAnnotation $ "extension"}}
+    {{$ext_name := index $ext.Arguments 0}}
+
+    {{$base := (Macro "BaseName" $)}}
+    {{$unnamed_params := (ForEach $.CallParameters "ParameterType" | JoinWith ", ")}}
+
+    VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$unnamed_params}}) {
+      ALOGE("{{$ext_name}} not enabled. {{$.Name}} not executed.");
+      {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}}
+    }
+    {{if (Macro "IsDeviceDispatched" $)}}
+      ¶
+      VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) {
+        {{if not (IsVoid $.Return.Type)}}return §{{end}}
+
+        {{$p0 := index $.CallParameters 0}}
+        {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}}
+        (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) ? §
+          {{$base}}({{Macro "Arguments" $}}) : §
+          disabled{{$base}}({{Macro "Arguments" $}});
+      }
+    {{end}}
+    ¶
+  {{end}}
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of a global ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineGlobalProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {{$ext := GetAnnotation $ "extension"}}
+  {{if $ext}}
+    {{Error "invalid global extension"}}
+  {{end}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::GLOBAL,
+    ProcHook::EXTENSION_CORE,
+    reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+    nullptr,
+    nullptr,
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of an instance ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineInstanceProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::INSTANCE,
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      ProcHook::{{Macro "BaseName" $ext}},
+
+      {{if (Macro "IsExtensionInternal" $ext)}}
+        nullptr,
+        nullptr,
+        nullptr,
+      {{else}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        nullptr,
+      {{end}}
+    {{else}}
+      ProcHook::EXTENSION_CORE,
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      nullptr,
+      nullptr,
+    {{end}}
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits definition of a device ProcHook.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.C++.DefineDeviceProcHook"}}
+  {{AssertType $ "Function"}}
+
+  {{$base := (Macro "BaseName" $)}}
+
+  {
+    "{{$.Name}}",
+    ProcHook::DEVICE,
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      ProcHook::{{Macro "BaseName" $ext}},
+
+      {{if (Macro "IsExtensionInternal" $ext)}}
+        nullptr,
+        nullptr,
+        nullptr,
+      {{else}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
+      {{end}}
+    {{else}}
+      ProcHook::EXTENSION_CORE,
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      nullptr,
+      nullptr,
+    {{end}}
+  },
+{{end}}
+
+
+{{/*
+-------------------------------------------------------------------------------
+  Emits true if a function is needed by vulkan::driver.
+-------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if (Macro "IsFunctionSupported" $)}}
+    {{/* Create functions of dispatchable objects */}}
+    {{     if eq $.Name "vkCreateDevice"}}true
+    {{else if eq $.Name "vkGetDeviceQueue"}}true
+    {{else if eq $.Name "vkAllocateCommandBuffers"}}true
+
+    {{/* Destroy functions of dispatchable objects */}}
+    {{else if eq $.Name "vkDestroyInstance"}}true
+    {{else if eq $.Name "vkDestroyDevice"}}true
+
+    {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
+
+    {{/* Enumeration of extensions */}}
+    {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
+
+    {{/* We cache physical devices in loader.cpp */}}
+    {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
+
+    {{else if eq $.Name "vkGetInstanceProcAddr"}}true
+    {{else if eq $.Name "vkGetDeviceProcAddr"}}true
+
+    {{/* VK_KHR_swapchain->VK_ANDROID_native_buffer translation */}}
+    {{else if eq $.Name "vkCreateImage"}}true
+    {{else if eq $.Name "vkDestroyImage"}}true
+
+    {{end}}
+
+    {{$ext := GetAnnotation $ "extension"}}
+    {{if $ext}}
+      {{$ext_name := index $ext.Arguments 0}}
+      {{     if eq $ext_name "VK_ANDROID_native_buffer"}}true
+      {{else if eq $ext_name "VK_EXT_debug_report"}}true
+      {{end}}
+    {{end}}
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if an instance-dispatched function is needed by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsInstanceDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsInstanceDispatched" $)}}
+    true
+  {{end}}
+{{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Emits true if a device-dispatched function is needed by vulkan::driver.
+------------------------------------------------------------------------------
+*/}}
+{{define "driver.IsDeviceDriverTableEntry"}}
+  {{AssertType $ "Function"}}
+
+  {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsDeviceDispatched" $)}}
+    true
+  {{end}}
+{{end}}
+
+
+{{/*
 -------------------------------------------------------------------------------
   Emits a function/extension name without the "vk"/"VK_" prefix.
 -------------------------------------------------------------------------------
@@ -517,3 +1033,16 @@
   {{else if eq $ext "VK_KHR_android_surface"}}true
   {{end}}
 {{end}}
+
+
+{{/*
+------------------------------------------------------------------------------
+  Reports whether an extension is internal to the loader and drivers,
+  so the loader should not enumerate it.
+------------------------------------------------------------------------------
+*/}}
+{{define "IsExtensionInternal"}}
+  {{$ext := index $.Arguments 0}}
+  {{     if eq $ext "VK_ANDROID_native_buffer"}}true
+  {{end}}
+{{end}}
diff --git a/vulkan/libvulkan/debug_report.cpp b/vulkan/libvulkan/debug_report.cpp
index 41b6040..c4a1174 100644
--- a/vulkan/libvulkan/debug_report.cpp
+++ b/vulkan/libvulkan/debug_report.cpp
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include "loader.h"
+#include "driver.h"
 
 namespace vulkan {
+namespace driver {
 
 VkResult DebugReportCallbackList::CreateCallback(
     VkInstance instance,
@@ -25,24 +26,22 @@
     VkDebugReportCallbackEXT* callback) {
     VkDebugReportCallbackEXT driver_callback = VK_NULL_HANDLE;
 
-    if (GetDriverDispatch(instance).CreateDebugReportCallbackEXT) {
-        VkResult result =
-            GetDriverDispatch(instance).CreateDebugReportCallbackEXT(
-                GetDriverInstance(instance), create_info, allocator,
-                &driver_callback);
+    if (GetData(instance).driver.CreateDebugReportCallbackEXT) {
+        VkResult result = GetData(instance).driver.CreateDebugReportCallbackEXT(
+            instance, create_info, allocator, &driver_callback);
         if (result != VK_SUCCESS)
             return result;
     }
 
     const VkAllocationCallbacks* alloc =
-        allocator ? allocator : GetAllocator(instance);
+        allocator ? allocator : &GetData(instance).allocator;
     void* mem =
         alloc->pfnAllocation(alloc->pUserData, sizeof(Node), alignof(Node),
                              VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
     if (!mem) {
-        if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
-            GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
-                GetDriverInstance(instance), driver_callback, allocator);
+        if (GetData(instance).driver.DestroyDebugReportCallbackEXT) {
+            GetData(instance).driver.DestroyDebugReportCallbackEXT(
+                instance, driver_callback, allocator);
         }
         return VK_ERROR_OUT_OF_HOST_MEMORY;
     }
@@ -68,13 +67,13 @@
     prev->next = node->next;
     lock.unlock();
 
-    if (GetDriverDispatch(instance).DestroyDebugReportCallbackEXT) {
-        GetDriverDispatch(instance).DestroyDebugReportCallbackEXT(
-            GetDriverInstance(instance), node->driver_callback, allocator);
+    if (GetData(instance).driver.DestroyDebugReportCallbackEXT) {
+        GetData(instance).driver.DestroyDebugReportCallbackEXT(
+            instance, node->driver_callback, allocator);
     }
 
     const VkAllocationCallbacks* alloc =
-        allocator ? allocator : GetAllocator(instance);
+        allocator ? allocator : &GetData(instance).allocator;
     alloc->pfnFree(alloc->pUserData, node);
 }
 
@@ -95,40 +94,40 @@
     }
 }
 
-VkResult CreateDebugReportCallbackEXT_Bottom(
+VkResult CreateDebugReportCallbackEXT(
     VkInstance instance,
     const VkDebugReportCallbackCreateInfoEXT* create_info,
     const VkAllocationCallbacks* allocator,
     VkDebugReportCallbackEXT* callback) {
-    return GetDebugReportCallbacks(instance).CreateCallback(
+    return GetData(instance).debug_report_callbacks.CreateCallback(
         instance, create_info, allocator, callback);
 }
 
-void DestroyDebugReportCallbackEXT_Bottom(
-    VkInstance instance,
-    VkDebugReportCallbackEXT callback,
-    const VkAllocationCallbacks* allocator) {
+void DestroyDebugReportCallbackEXT(VkInstance instance,
+                                   VkDebugReportCallbackEXT callback,
+                                   const VkAllocationCallbacks* allocator) {
     if (callback)
-        GetDebugReportCallbacks(instance).DestroyCallback(instance, callback,
-                                                          allocator);
+        GetData(instance).debug_report_callbacks.DestroyCallback(
+            instance, callback, allocator);
 }
 
-void DebugReportMessageEXT_Bottom(VkInstance instance,
-                                  VkDebugReportFlagsEXT flags,
-                                  VkDebugReportObjectTypeEXT object_type,
-                                  uint64_t object,
-                                  size_t location,
-                                  int32_t message_code,
-                                  const char* layer_prefix,
-                                  const char* message) {
-    if (GetDriverDispatch(instance).DebugReportMessageEXT) {
-        GetDriverDispatch(instance).DebugReportMessageEXT(
-            GetDriverInstance(instance), flags, object_type, object, location,
-            message_code, layer_prefix, message);
+void DebugReportMessageEXT(VkInstance instance,
+                           VkDebugReportFlagsEXT flags,
+                           VkDebugReportObjectTypeEXT object_type,
+                           uint64_t object,
+                           size_t location,
+                           int32_t message_code,
+                           const char* layer_prefix,
+                           const char* message) {
+    if (GetData(instance).driver.DebugReportMessageEXT) {
+        GetData(instance).driver.DebugReportMessageEXT(
+            instance, flags, object_type, object, location, message_code,
+            layer_prefix, message);
     }
-    GetDebugReportCallbacks(instance).Message(flags, object_type, object,
-                                              location, message_code,
-                                              layer_prefix, message);
+    GetData(instance).debug_report_callbacks.Message(flags, object_type, object,
+                                                     location, message_code,
+                                                     layer_prefix, message);
 }
 
+}  // namespace driver
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index c6f7570..72b1887 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -17,14 +17,16 @@
 #ifndef LIBVULKAN_DEBUG_REPORT_H
 #define LIBVULKAN_DEBUG_REPORT_H 1
 
+#include <vulkan/vulkan.h>
 #include <shared_mutex>
 
 namespace vulkan {
+namespace driver {
 
 // clang-format off
-VKAPI_ATTR VkResult CreateDebugReportCallbackEXT_Bottom(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
-VKAPI_ATTR void DestroyDebugReportCallbackEXT_Bottom(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void DebugReportMessageEXT_Bottom(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
+VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
+VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
 // clang-format on
 
 class DebugReportCallbackList {
@@ -65,6 +67,7 @@
     Node head_;
 };
 
+}  // namespace driver
 }  // namespace vulkan
 
 #endif  // LIBVULKAN_DEBUG_REPORT_H
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
deleted file mode 100644
index 67ead4a..0000000
--- a/vulkan/libvulkan/dispatch.tmpl
+++ /dev/null
@@ -1,365 +0,0 @@
-{{/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */}}
-
-{{Include "../api/templates/vulkan_common.tmpl"}}
-{{Global "clang-format" (Strings "clang-format" "-style=file")}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "dispatch_gen.h"   | Format (Global "clang-format") | Write "dispatch_gen.h"  }}
-{{$ | Macro "dispatch_gen.cpp" | Format (Global "clang-format") | Write "dispatch_gen.cpp"}}
-
-{{/*
--------------------------------------------------------------------------------
-  dispatch_gen.h
--------------------------------------------------------------------------------
-*/}}
-{{define "dispatch_gen.h"}}
-/*
-•* Copyright 2015 The Android Open Source Project
-•*
-•* Licensed under the Apache License, Version 2.0 (the "License");
-•* you may not use this file except in compliance with the License.
-•* You may obtain a copy of the License at
-•*
-•*      http://www.apache.org/licenses/LICENSE-2.0
-•*
-•* Unless required by applicable law or agreed to in writing, software
-•* distributed under the License is distributed on an "AS IS" BASIS,
-•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-•* See the License for the specific language governing permissions and
-•* limitations under the License.
-•*/

-// WARNING: This file is generated. See ../README.md for instructions.

-#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vulkan.h>

-namespace vulkan {

-struct DriverDispatchTable {«
-  // clang-format off
-  {{range $f := AllCommands $}}
-    {{if (Macro "IsInstanceDispatched" $f)}}
-      {{if not (Macro "IsLoaderFunction" $f)}}
-        {{Macro "FunctionPtrName" $f}} {{Macro "BaseName" $f}};
-      {{end}}
-    {{end}}
-  {{end}}
-
-    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
-
-    PFN_vkDestroyDevice DestroyDevice;
-    PFN_vkGetDeviceQueue GetDeviceQueue;
-    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
-
-    {{/* TODO(jessehall): Needed by swapchain code. Figure out a better way of
-         handling this that avoids the special case. Probably should rework
-         things so the driver dispatch table has all driver functions. Probably
-         need separate instance- and device-level copies, fill in all device-
-         dispatched functions in the device-level copies only, and change
-         GetDeviceProcAddr_Bottom to look in the already-loaded driver
-         dispatch table rather than forwarding to the driver's
-         vkGetDeviceProcAddr. */}}
-    PFN_vkCreateImage CreateImage;
-    PFN_vkDestroyImage DestroyImage;
-
-    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
-    PFN_vkAcquireImageANDROID AcquireImageANDROID;
-    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
-  // clang-format on
-»};

-} // namespace vulkan
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  dispatch_gen.cpp
--------------------------------------------------------------------------------
-*/}}
-{{define "dispatch_gen.cpp"}}
-/*
-•* Copyright 2015 The Android Open Source Project
-•*
-•* Licensed under the Apache License, Version 2.0 (the "License");
-•* you may not use this file except in compliance with the License.
-•* You may obtain a copy of the License at
-•*
-•*      http://www.apache.org/licenses/LICENSE-2.0
-•*
-•* Unless required by applicable law or agreed to in writing, software
-•* distributed under the License is distributed on an "AS IS" BASIS,
-•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-•* See the License for the specific language governing permissions and
-•* limitations under the License.
-•*/

-// WARNING: This file is generated. See ../README.md for instructions.

-#include <log/log.h>
-#include <algorithm>
-#include "loader.h"

-#define UNLIKELY(expr) __builtin_expect((expr), 0)

-using namespace vulkan;

-namespace {

-struct NameProc {
-    const char* name;
-    PFN_vkVoidFunction proc;
-};

-PFN_vkVoidFunction Lookup(const char* name, const NameProc* begin, const NameProc* end) {
-    const auto& entry = std::lower_bound(
-        begin, end, name,
-        [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
-    if (entry == end || strcmp(entry->name, name) != 0)
-        return nullptr;
-    return entry->proc;
-}

-template <size_t N>
-PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
-    return Lookup(name, procs, procs + N);
-}

-const NameProc kLoaderBottomProcs[] = {«
-    // clang-format off
-  {{range $f := SortBy (AllCommands $) "FunctionName"}}
-    {{if (Macro "HasLoaderBottomImpl" $f)}}
-    {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
-        static_cast<{{Macro "FunctionPtrName" $f}}>(§
-            {{Macro "BaseName" $f}}_Bottom))},
-    {{end}}
-  {{end}}
-    // clang-format on
-»};

-} // anonymous namespace

-namespace vulkan {

-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
-    return Lookup(name, kLoaderBottomProcs);
-}

-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch) {«
-    bool success = true;
-    // clang-format off
-  {{range $f := AllCommands $}}
-    {{if (Macro "IsInstanceDispatched" $f)}}
-      {{if not (Macro "IsLoaderFunction" $f)}}
-        {{$ext := GetAnnotation $f "extension"}}
-          {{if $ext}}
-    if (extensions[{{Macro "ExtensionConstant" $ext}}]) {
-          {{end}}
-        dispatch.{{Macro "BaseName" $f}} = §
-            reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
-                get_proc_addr(instance, "{{$f.Name}}"));
-        if (UNLIKELY(!dispatch.{{Macro "BaseName" $f}})) {
-            ALOGE("missing driver proc: %s", "{{$f.Name}}");
-            success = false;
-        }
-        {{if $ext}}
-    }
-        {{end}}
-      {{end}}
-    {{end}}
-  {{end}}
-    dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
-    if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
-        success = false;
-    }
-    dispatch.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(get_proc_addr(instance, "vkDestroyDevice"));
-    if (UNLIKELY(!dispatch.DestroyDevice)) {
-        ALOGE("missing driver proc: %s", "vkDestroyDevice");
-        success = false;
-    }
-    dispatch.GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(get_proc_addr(instance, "vkGetDeviceQueue"));
-    if (UNLIKELY(!dispatch.GetDeviceQueue)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceQueue");
-        success = false;
-    }
-    dispatch.AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(get_proc_addr(instance, "vkAllocateCommandBuffers"));
-    if (UNLIKELY(!dispatch.AllocateCommandBuffers)) {
-        ALOGE("missing driver proc: %s", "vkAllocateCommandBuffers");
-        success = false;
-    }
-    dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
-    if (UNLIKELY(!dispatch.CreateImage)) {
-        ALOGE("missing driver proc: %s", "vkCreateImage");
-        success = false;
-    }
-    dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
-    if (UNLIKELY(!dispatch.DestroyImage)) {
-        ALOGE("missing driver proc: %s", "vkDestroyImage");
-        success = false;
-    }
-    dispatch.GetSwapchainGrallocUsageANDROID = reinterpret_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(get_proc_addr(instance, "vkGetSwapchainGrallocUsageANDROID"));
-    if (UNLIKELY(!dispatch.GetSwapchainGrallocUsageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkGetSwapchainGrallocUsageANDROID");
-        success = false;
-    }
-    dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
-    if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
-        success = false;
-    }
-    dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
-    if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
-        success = false;
-    }
-    // clang-format on
-    return success;
-»}

-} // namespace vulkan
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Map an extension name to InstanceExtension or DeviceExtension enum value
--------------------------------------------------------------------------------
-*/}}
-{{define "ExtensionConstant"}}
-  {{$name := index $.Arguments 0}}
-  {{     if (eq $name "VK_KHR_surface")}}kKHR_surface
-  {{else if (eq $name "VK_KHR_android_surface")}}kKHR_android_surface
-  {{else if (eq $name "VK_EXT_debug_report")}}kEXT_debug_report
-  {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Emits a function name without the "vk" prefix.
--------------------------------------------------------------------------------
-*/}}
-{{define "BaseName"}}
-  {{AssertType $ "Function"}}
-  {{TrimPrefix "vk" $.Name}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" for supported functions that undergo table dispatch. Only global
-  functions and functions handled in the loader top without calling into
-  lower layers are not dispatched.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsInstanceDispatched"}}
-  {{AssertType $ "Function"}}
-  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
-    {{if and (ne $.Name "vkEnumerateDeviceLayerProperties") (ne $.Name "vkGetInstanceProcAddr")}}true{{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" if a function is core or from a supportable extension.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsFunctionSupported"}}
-  {{AssertType $ "Function"}}
-  {{if not (GetAnnotation $ "pfn")}}
-    {{$ext := GetAnnotation $ "extension"}}
-    {{if not $ext}}true
-    {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
-    {{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Reports whether an extension function is implemented entirely by the loader,
-  and not implemented by drivers.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsLoaderFunction"}}
-  {{AssertType $ "Function"}}
-
-  {{$ext := GetAnnotation $ "extension"}}
-  {{if $ext}}
-    {{Macro "IsLoaderExtension" $ext}}
-  {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
-  Emit "true" if the loader has a bottom-level implementation for the function
-  which terminates the dispatch chain.
--------------------------------------------------------------------------------
-*/}}
-{{define "HasLoaderBottomImpl"}}
-  {{AssertType $ "Function"}}
-
-  {{if (Macro "IsFunctionSupported" $)}}
-    {{     if (eq (Macro "Vtbl" $) "Instance")}}true
-    {{else if (Macro "IsLoaderFunction" $)}}true
-    {{else if (eq $.Name "vkCreateInstance")}}true
-    {{else if (eq $.Name "vkGetDeviceProcAddr")}}true
-    {{else if (eq $.Name "vkDestroyDevice")}}true
-    {{else if (eq $.Name "vkGetDeviceQueue")}}true
-    {{else if (eq $.Name "vkAllocateCommandBuffers")}}true
-    {{end}}
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Emit "true" if an extension is unsupportable on Android.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsExtensionBlacklisted"}}
-  {{$ext := index $.Arguments 0}}
-  {{     if eq $ext "VK_KHR_display"}}true
-  {{else if eq $ext "VK_KHR_display_swapchain"}}true
-  {{else if eq $ext "VK_KHR_xlib_surface"}}true
-  {{else if eq $ext "VK_KHR_xcb_surface"}}true
-  {{else if eq $ext "VK_KHR_wayland_surface"}}true
-  {{else if eq $ext "VK_KHR_mir_surface"}}true
-  {{else if eq $ext "VK_KHR_win32_surface"}}true
-  {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-  Reports whether an extension is implemented entirely by the loader,
-  so drivers should not enumerate it.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsLoaderExtension"}}
-  {{$ext := index $.Arguments 0}}
-  {{     if eq $ext "VK_KHR_surface"}}true
-  {{else if eq $ext "VK_KHR_swapchain"}}true
-  {{else if eq $ext "VK_KHR_android_surface"}}true
-  {{end}}
-{{end}}
diff --git a/vulkan/libvulkan/dispatch_gen.cpp b/vulkan/libvulkan/dispatch_gen.cpp
deleted file mode 100644
index eacf1a1..0000000
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// WARNING: This file is generated. See ../README.md for instructions.
-
-#include <log/log.h>
-#include <algorithm>
-#include "loader.h"
-
-#define UNLIKELY(expr) __builtin_expect((expr), 0)
-
-using namespace vulkan;
-
-namespace {
-
-struct NameProc {
-    const char* name;
-    PFN_vkVoidFunction proc;
-};
-
-PFN_vkVoidFunction Lookup(const char* name,
-                          const NameProc* begin,
-                          const NameProc* end) {
-    const auto& entry = std::lower_bound(
-        begin, end, name,
-        [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
-    if (entry == end || strcmp(entry->name, name) != 0)
-        return nullptr;
-    return entry->proc;
-}
-
-template <size_t N>
-PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
-    return Lookup(name, procs, procs + N);
-}
-
-const NameProc kLoaderBottomProcs[] = {
-    // clang-format off
-    {"vkAcquireNextImageKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireNextImageKHR>(AcquireNextImageKHR_Bottom))},
-    {"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers_Bottom))},
-    {"vkCreateAndroidSurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateAndroidSurfaceKHR>(CreateAndroidSurfaceKHR_Bottom))},
-    {"vkCreateDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDebugReportCallbackEXT>(CreateDebugReportCallbackEXT_Bottom))},
-    {"vkCreateDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateDevice>(CreateDevice_Bottom))},
-    {"vkCreateInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateInstance>(CreateInstance_Bottom))},
-    {"vkCreateSwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSwapchainKHR>(CreateSwapchainKHR_Bottom))},
-    {"vkDebugReportMessageEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDebugReportMessageEXT>(DebugReportMessageEXT_Bottom))},
-    {"vkDestroyDebugReportCallbackEXT", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDebugReportCallbackEXT>(DestroyDebugReportCallbackEXT_Bottom))},
-    {"vkDestroyDevice", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyDevice>(DestroyDevice_Bottom))},
-    {"vkDestroyInstance", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroyInstance>(DestroyInstance_Bottom))},
-    {"vkDestroySurfaceKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySurfaceKHR>(DestroySurfaceKHR_Bottom))},
-    {"vkDestroySwapchainKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkDestroySwapchainKHR>(DestroySwapchainKHR_Bottom))},
-    {"vkEnumerateDeviceExtensionProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceExtensionProperties>(EnumerateDeviceExtensionProperties_Bottom))},
-    {"vkEnumerateDeviceLayerProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumerateDeviceLayerProperties>(EnumerateDeviceLayerProperties_Bottom))},
-    {"vkEnumeratePhysicalDevices", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkEnumeratePhysicalDevices>(EnumeratePhysicalDevices_Bottom))},
-    {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr_Bottom))},
-    {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue_Bottom))},
-    {"vkGetInstanceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetInstanceProcAddr>(GetInstanceProcAddr_Bottom))},
-    {"vkGetPhysicalDeviceFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFeatures>(GetPhysicalDeviceFeatures_Bottom))},
-    {"vkGetPhysicalDeviceFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceFormatProperties>(GetPhysicalDeviceFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(GetPhysicalDeviceImageFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceMemoryProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(GetPhysicalDeviceMemoryProperties_Bottom))},
-    {"vkGetPhysicalDeviceProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceProperties>(GetPhysicalDeviceProperties_Bottom))},
-    {"vkGetPhysicalDeviceQueueFamilyProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(GetPhysicalDeviceQueueFamilyProperties_Bottom))},
-    {"vkGetPhysicalDeviceSparseImageFormatProperties", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(GetPhysicalDeviceSparseImageFormatProperties_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceFormatsKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(GetPhysicalDeviceSurfaceFormatsKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(GetPhysicalDeviceSurfacePresentModesKHR_Bottom))},
-    {"vkGetPhysicalDeviceSurfaceSupportKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(GetPhysicalDeviceSurfaceSupportKHR_Bottom))},
-    {"vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainImagesKHR>(GetSwapchainImagesKHR_Bottom))},
-    {"vkQueuePresentKHR", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueuePresentKHR>(QueuePresentKHR_Bottom))},
-    // clang-format on
-};
-
-}  // anonymous namespace
-
-namespace vulkan {
-
-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name) {
-    return Lookup(name, kLoaderBottomProcs);
-}
-
-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch) {
-    bool success = true;
-    // clang-format off
-    dispatch.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(get_proc_addr(instance, "vkDestroyInstance"));
-    if (UNLIKELY(!dispatch.DestroyInstance)) {
-        ALOGE("missing driver proc: %s", "vkDestroyInstance");
-        success = false;
-    }
-    dispatch.EnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(get_proc_addr(instance, "vkEnumeratePhysicalDevices"));
-    if (UNLIKELY(!dispatch.EnumeratePhysicalDevices)) {
-        ALOGE("missing driver proc: %s", "vkEnumeratePhysicalDevices");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceQueueFamilyProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceQueueFamilyProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceMemoryProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceMemoryProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceMemoryProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceFeatures = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(get_proc_addr(instance, "vkGetPhysicalDeviceFeatures"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceFeatures)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceFeatures");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceFormatProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceImageFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceImageFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceImageFormatProperties");
-        success = false;
-    }
-    dispatch.CreateDevice = reinterpret_cast<PFN_vkCreateDevice>(get_proc_addr(instance, "vkCreateDevice"));
-    if (UNLIKELY(!dispatch.CreateDevice)) {
-        ALOGE("missing driver proc: %s", "vkCreateDevice");
-        success = false;
-    }
-    dispatch.EnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(get_proc_addr(instance, "vkEnumerateDeviceExtensionProperties"));
-    if (UNLIKELY(!dispatch.EnumerateDeviceExtensionProperties)) {
-        ALOGE("missing driver proc: %s", "vkEnumerateDeviceExtensionProperties");
-        success = false;
-    }
-    dispatch.GetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceSparseImageFormatProperties"));
-    if (UNLIKELY(!dispatch.GetPhysicalDeviceSparseImageFormatProperties)) {
-        ALOGE("missing driver proc: %s", "vkGetPhysicalDeviceSparseImageFormatProperties");
-        success = false;
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.CreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(get_proc_addr(instance, "vkCreateDebugReportCallbackEXT"));
-        if (UNLIKELY(!dispatch.CreateDebugReportCallbackEXT)) {
-            ALOGE("missing driver proc: %s", "vkCreateDebugReportCallbackEXT");
-            success = false;
-        }
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.DestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(get_proc_addr(instance, "vkDestroyDebugReportCallbackEXT"));
-        if (UNLIKELY(!dispatch.DestroyDebugReportCallbackEXT)) {
-            ALOGE("missing driver proc: %s", "vkDestroyDebugReportCallbackEXT");
-            success = false;
-        }
-    }
-    if (extensions[kEXT_debug_report]) {
-        dispatch.DebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(get_proc_addr(instance, "vkDebugReportMessageEXT"));
-        if (UNLIKELY(!dispatch.DebugReportMessageEXT)) {
-            ALOGE("missing driver proc: %s", "vkDebugReportMessageEXT");
-            success = false;
-        }
-    }
-    dispatch.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(instance, "vkGetDeviceProcAddr"));
-    if (UNLIKELY(!dispatch.GetDeviceProcAddr)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceProcAddr");
-        success = false;
-    }
-    dispatch.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(get_proc_addr(instance, "vkDestroyDevice"));
-    if (UNLIKELY(!dispatch.DestroyDevice)) {
-        ALOGE("missing driver proc: %s", "vkDestroyDevice");
-        success = false;
-    }
-    dispatch.GetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(get_proc_addr(instance, "vkGetDeviceQueue"));
-    if (UNLIKELY(!dispatch.GetDeviceQueue)) {
-        ALOGE("missing driver proc: %s", "vkGetDeviceQueue");
-        success = false;
-    }
-    dispatch.AllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(get_proc_addr(instance, "vkAllocateCommandBuffers"));
-    if (UNLIKELY(!dispatch.AllocateCommandBuffers)) {
-        ALOGE("missing driver proc: %s", "vkAllocateCommandBuffers");
-        success = false;
-    }
-    dispatch.CreateImage = reinterpret_cast<PFN_vkCreateImage>(get_proc_addr(instance, "vkCreateImage"));
-    if (UNLIKELY(!dispatch.CreateImage)) {
-        ALOGE("missing driver proc: %s", "vkCreateImage");
-        success = false;
-    }
-    dispatch.DestroyImage = reinterpret_cast<PFN_vkDestroyImage>(get_proc_addr(instance, "vkDestroyImage"));
-    if (UNLIKELY(!dispatch.DestroyImage)) {
-        ALOGE("missing driver proc: %s", "vkDestroyImage");
-        success = false;
-    }
-    dispatch.GetSwapchainGrallocUsageANDROID = reinterpret_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(get_proc_addr(instance, "vkGetSwapchainGrallocUsageANDROID"));
-    if (UNLIKELY(!dispatch.GetSwapchainGrallocUsageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkGetSwapchainGrallocUsageANDROID");
-        success = false;
-    }
-    dispatch.AcquireImageANDROID = reinterpret_cast<PFN_vkAcquireImageANDROID>(get_proc_addr(instance, "vkAcquireImageANDROID"));
-    if (UNLIKELY(!dispatch.AcquireImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkAcquireImageANDROID");
-        success = false;
-    }
-    dispatch.QueueSignalReleaseImageANDROID = reinterpret_cast<PFN_vkQueueSignalReleaseImageANDROID>(get_proc_addr(instance, "vkQueueSignalReleaseImageANDROID"));
-    if (UNLIKELY(!dispatch.QueueSignalReleaseImageANDROID)) {
-        ALOGE("missing driver proc: %s", "vkQueueSignalReleaseImageANDROID");
-        success = false;
-    }
-    // clang-format on
-    return success;
-}
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/dispatch_gen.h b/vulkan/libvulkan/dispatch_gen.h
deleted file mode 100644
index ca31caf..0000000
--- a/vulkan/libvulkan/dispatch_gen.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// WARNING: This file is generated. See ../README.md for instructions.
-
-#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vulkan.h>
-
-namespace vulkan {
-
-struct DriverDispatchTable {
-    // clang-format off
-    PFN_vkDestroyInstance DestroyInstance;
-    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
-    PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
-    PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties;
-    PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties;
-    PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures;
-    PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;
-    PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;
-    PFN_vkCreateDevice CreateDevice;
-    PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
-    PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
-    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
-    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
-    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
-    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
-    PFN_vkDestroyDevice DestroyDevice;
-    PFN_vkGetDeviceQueue GetDeviceQueue;
-    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
-    PFN_vkCreateImage CreateImage;
-    PFN_vkDestroyImage DestroyImage;
-    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
-    PFN_vkAcquireImageANDROID AcquireImageANDROID;
-    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
-    // clang-format on
-};
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
new file mode 100644
index 0000000..007c54d
--- /dev/null
+++ b/vulkan/libvulkan/driver.cpp
@@ -0,0 +1,769 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include <array>
+#include <new>
+#include <malloc.h>
+#include <sys/prctl.h>
+
+#include "driver.h"
+
+// #define ENABLE_ALLOC_CALLSTACKS 1
+#if ENABLE_ALLOC_CALLSTACKS
+#include <utils/CallStack.h>
+#define ALOGD_CALLSTACK(...)                             \
+    do {                                                 \
+        ALOGD(__VA_ARGS__);                              \
+        android::CallStack callstack;                    \
+        callstack.update();                              \
+        callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, "  "); \
+    } while (false)
+#else
+#define ALOGD_CALLSTACK(...) \
+    do {                     \
+    } while (false)
+#endif
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+class CreateInfoWrapper {
+   public:
+    CreateInfoWrapper(hwvulkan_device_t* hw_dev,
+                      const VkInstanceCreateInfo& create_info,
+                      const VkAllocationCallbacks& allocator);
+    CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                      const VkDeviceCreateInfo& create_info,
+                      const VkAllocationCallbacks& allocator);
+    ~CreateInfoWrapper();
+
+    VkResult validate();
+
+    const std::bitset<ProcHook::EXTENSION_COUNT>& get_hook_extensions() const;
+    const std::bitset<ProcHook::EXTENSION_COUNT>& get_hal_extensions() const;
+
+    explicit operator const VkInstanceCreateInfo*() const;
+    explicit operator const VkDeviceCreateInfo*() const;
+
+   private:
+    struct ExtensionFilter {
+        VkExtensionProperties* exts;
+        uint32_t ext_count;
+
+        const char** names;
+        uint32_t name_count;
+    };
+
+    VkResult sanitize_pnext();
+
+    VkResult sanitize_layers();
+    VkResult sanitize_extensions();
+
+    VkResult query_extension_count(uint32_t& count) const;
+    VkResult enumerate_extensions(uint32_t& count,
+                                  VkExtensionProperties* props) const;
+    VkResult init_extension_filter();
+    void filter_extension(const char* name);
+
+    const bool is_instance_;
+    const VkAllocationCallbacks& allocator_;
+
+    union {
+        hwvulkan_device_t* hw_dev_;
+        VkPhysicalDevice physical_dev_;
+    };
+
+    union {
+        VkInstanceCreateInfo instance_info_;
+        VkDeviceCreateInfo dev_info_;
+    };
+
+    ExtensionFilter extension_filter_;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions_;
+};
+
+CreateInfoWrapper::CreateInfoWrapper(hwvulkan_device_t* hw_dev,
+                                     const VkInstanceCreateInfo& create_info,
+                                     const VkAllocationCallbacks& allocator)
+    : is_instance_(true),
+      allocator_(allocator),
+      hw_dev_(hw_dev),
+      instance_info_(create_info),
+      extension_filter_() {
+    hook_extensions_.set(ProcHook::EXTENSION_CORE);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+}
+
+CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                                     const VkDeviceCreateInfo& create_info,
+                                     const VkAllocationCallbacks& allocator)
+    : is_instance_(false),
+      allocator_(allocator),
+      physical_dev_(physical_dev),
+      dev_info_(create_info),
+      extension_filter_() {
+    hook_extensions_.set(ProcHook::EXTENSION_CORE);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+}
+
+CreateInfoWrapper::~CreateInfoWrapper() {
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
+}
+
+VkResult CreateInfoWrapper::validate() {
+    VkResult result = sanitize_pnext();
+    if (result == VK_SUCCESS)
+        result = sanitize_layers();
+    if (result == VK_SUCCESS)
+        result = sanitize_extensions();
+
+    return result;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::get_hook_extensions() const {
+    return hook_extensions_;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::get_hal_extensions() const {
+    return hal_extensions_;
+}
+
+CreateInfoWrapper::operator const VkInstanceCreateInfo*() const {
+    return &instance_info_;
+}
+
+CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
+    return &dev_info_;
+}
+
+VkResult CreateInfoWrapper::sanitize_pnext() {
+    const struct StructHeader {
+        VkStructureType type;
+        const void* next;
+    } * header;
+
+    if (is_instance_) {
+        header = reinterpret_cast<const StructHeader*>(instance_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        instance_info_.pNext = header;
+    } else {
+        header = reinterpret_cast<const StructHeader*>(dev_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        dev_info_.pNext = header;
+    }
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::sanitize_layers() {
+    auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames
+                                       : dev_info_.ppEnabledLayerNames;
+    auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount
+                                       : dev_info_.enabledLayerCount;
+
+    // remove all layers
+    layer_names = nullptr;
+    layer_count = 0;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::sanitize_extensions() {
+    auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames
+                                     : dev_info_.ppEnabledExtensionNames;
+    auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    if (!ext_count)
+        return VK_SUCCESS;
+
+    VkResult result = init_extension_filter();
+    if (result != VK_SUCCESS)
+        return result;
+
+    for (uint32_t i = 0; i < ext_count; i++)
+        filter_extension(ext_names[i]);
+
+    ext_names = extension_filter_.names;
+    ext_count = extension_filter_.name_count;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::query_extension_count(uint32_t& count) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             nullptr);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, nullptr);
+    }
+}
+
+VkResult CreateInfoWrapper::enumerate_extensions(
+    uint32_t& count,
+    VkExtensionProperties* props) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             props);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, props);
+    }
+}
+
+VkResult CreateInfoWrapper::init_extension_filter() {
+    // query extension count
+    uint32_t count;
+    VkResult result = query_extension_count(count);
+    if (result != VK_SUCCESS || count == 0)
+        return result;
+
+    auto& filter = extension_filter_;
+    filter.exts =
+        reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
+            allocator_.pUserData, sizeof(VkExtensionProperties) * count,
+            alignof(VkExtensionProperties),
+            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.exts)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    // enumerate extensions
+    result = enumerate_extensions(count, filter.exts);
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
+        return result;
+
+    if (!count)
+        return VK_SUCCESS;
+
+    filter.ext_count = count;
+
+    // allocate name array
+    uint32_t enabled_ext_count = (is_instance_)
+                                     ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    count = std::min(filter.ext_count, enabled_ext_count);
+    filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
+        allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
+        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.names)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    return VK_SUCCESS;
+}
+
+void CreateInfoWrapper::filter_extension(const char* name) {
+    auto& filter = extension_filter_;
+
+    ProcHook::Extension ext_bit = GetProcHookExtension(name);
+    if (is_instance_) {
+        switch (ext_bit) {
+            case ProcHook::KHR_android_surface:
+            case ProcHook::KHR_surface:
+                hook_extensions_.set(ext_bit);
+                // return now as these extensions do not require HAL support
+                return;
+            case ProcHook::EXT_debug_report:
+                // both we and HAL can take part in
+                hook_extensions_.set(ext_bit);
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid instance extension %s", name);
+                return;
+        }
+    } else {
+        switch (ext_bit) {
+            case ProcHook::KHR_swapchain:
+                // map VK_KHR_swapchain to VK_ANDROID_native_buffer
+                name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+                ext_bit = ProcHook::ANDROID_native_buffer;
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid device extension %s", name);
+                return;
+        }
+    }
+
+    for (uint32_t i = 0; i < filter.ext_count; i++) {
+        const VkExtensionProperties& props = filter.exts[i];
+        // ignore unknown extensions
+        if (strcmp(name, props.extensionName) != 0)
+            continue;
+
+        if (ext_bit == ProcHook::ANDROID_native_buffer)
+            hook_extensions_.set(ProcHook::KHR_swapchain);
+
+        filter.names[filter.name_count++] = name;
+        hal_extensions_.set(ext_bit);
+
+        break;
+    }
+}
+
+hwvulkan_device_t* g_hwdevice = nullptr;
+
+VKAPI_ATTR void* DefaultAllocate(void*,
+                                 size_t size,
+                                 size_t alignment,
+                                 VkSystemAllocationScope) {
+    void* ptr = nullptr;
+    // Vulkan requires 'alignment' to be a power of two, but posix_memalign
+    // additionally requires that it be at least sizeof(void*).
+    int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
+    ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
+                    ret, ptr);
+    return ret == 0 ? ptr : nullptr;
+}
+
+VKAPI_ATTR void* DefaultReallocate(void*,
+                                   void* ptr,
+                                   size_t size,
+                                   size_t alignment,
+                                   VkSystemAllocationScope) {
+    if (size == 0) {
+        free(ptr);
+        return nullptr;
+    }
+
+    // TODO(jessehall): Right now we never shrink allocations; if the new
+    // request is smaller than the existing chunk, we just continue using it.
+    // Right now the loader never reallocs, so this doesn't matter. If that
+    // changes, or if this code is copied into some other project, this should
+    // probably have a heuristic to allocate-copy-free when doing so will save
+    // "enough" space.
+    size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
+    if (size <= old_size)
+        return ptr;
+
+    void* new_ptr = nullptr;
+    if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
+        return nullptr;
+    if (ptr) {
+        memcpy(new_ptr, ptr, std::min(old_size, size));
+        free(ptr);
+    }
+    return new_ptr;
+}
+
+VKAPI_ATTR void DefaultFree(void*, void* ptr) {
+    ALOGD_CALLSTACK("Free: %p", ptr);
+    free(ptr);
+}
+
+InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
+    void* data_mem = allocator.pfnAllocation(
+        allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
+        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+    if (!data_mem)
+        return nullptr;
+
+    return new (data_mem) InstanceData(allocator);
+}
+
+void FreeInstanceData(InstanceData* data,
+                      const VkAllocationCallbacks& allocator) {
+    data->~InstanceData();
+    allocator.pfnFree(allocator.pUserData, data);
+}
+
+DeviceData* AllocateDeviceData(const VkAllocationCallbacks& allocator) {
+    void* data_mem = allocator.pfnAllocation(
+        allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
+        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+    if (!data_mem)
+        return nullptr;
+
+    return new (data_mem) DeviceData(allocator);
+}
+
+void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
+    data->~DeviceData();
+    allocator.pfnFree(allocator.pUserData, data);
+}
+
+}  // anonymous namespace
+
+bool Debuggable() {
+    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
+}
+
+bool OpenHAL() {
+    if (g_hwdevice)
+        return true;
+
+    const hwvulkan_module_t* module;
+    int result =
+        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
+    if (result != 0) {
+        ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result);
+        return false;
+    }
+
+    hwvulkan_device_t* device;
+    result =
+        module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
+                                     reinterpret_cast<hw_device_t**>(&device));
+    if (result != 0) {
+        ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result),
+              result);
+        return false;
+    }
+
+    g_hwdevice = device;
+
+    return true;
+}
+
+const VkAllocationCallbacks& GetDefaultAllocator() {
+    static const VkAllocationCallbacks kDefaultAllocCallbacks = {
+        .pUserData = nullptr,
+        .pfnAllocation = DefaultAllocate,
+        .pfnReallocation = DefaultReallocate,
+        .pfnFree = DefaultFree,
+    };
+
+    return kDefaultAllocCallbacks;
+}
+
+PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
+    const ProcHook* hook = GetProcHook(pName);
+    if (!hook)
+        return g_hwdevice->GetInstanceProcAddr(instance, pName);
+
+    if (!instance) {
+        if (hook->type == ProcHook::GLOBAL)
+            return hook->proc;
+
+        ALOGE(
+            "Invalid use of vkGetInstanceProcAddr to query %s without an "
+            "instance",
+            pName);
+
+        // Some naughty layers expect
+        //
+        //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
+        //
+        // to work.
+        return (strcmp(pName, "vkCreateDevice") == 0) ? hook->proc : nullptr;
+    }
+
+    PFN_vkVoidFunction proc;
+
+    switch (hook->type) {
+        case ProcHook::INSTANCE:
+            proc = (GetData(instance).hook_extensions[hook->extension])
+                       ? hook->proc
+                       : hook->disabled_proc;
+            break;
+        case ProcHook::DEVICE:
+            proc = (hook->extension == ProcHook::EXTENSION_CORE)
+                       ? hook->proc
+                       : hook->checked_proc;
+            break;
+        default:
+            ALOGE(
+                "Invalid use of vkGetInstanceProcAddr to query %s with an "
+                "instance",
+                pName);
+            proc = nullptr;
+            break;
+    }
+
+    return proc;
+}
+
+PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
+    const ProcHook* hook = GetProcHook(pName);
+    if (!hook)
+        return GetData(device).driver.GetDeviceProcAddr(device, pName);
+
+    if (hook->type != ProcHook::DEVICE) {
+        ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
+        return nullptr;
+    }
+
+    return (GetData(device).hook_extensions[hook->extension])
+               ? hook->proc
+               : hook->disabled_proc;
+}
+
+VkResult EnumerateInstanceExtensionProperties(
+    const char* pLayerName,
+    uint32_t* pPropertyCount,
+    VkExtensionProperties* pProperties) {
+    static const std::array<VkExtensionProperties, 2> loader_extensions = {{
+        // WSI extensions
+        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
+        {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+         VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
+    }};
+
+    // enumerate our extensions first
+    if (!pLayerName && pProperties) {
+        uint32_t count = std::min(
+            *pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
+
+        std::copy_n(loader_extensions.begin(), count, pProperties);
+
+        if (count < loader_extensions.size()) {
+            *pPropertyCount = count;
+            return VK_INCOMPLETE;
+        }
+
+        pProperties += count;
+        *pPropertyCount -= count;
+    }
+
+    VkResult result = g_hwdevice->EnumerateInstanceExtensionProperties(
+        pLayerName, pPropertyCount, pProperties);
+
+    if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE))
+        *pPropertyCount += loader_extensions.size();
+
+    return result;
+}
+
+VkResult EnumerateDeviceExtensionProperties(
+    VkPhysicalDevice physicalDevice,
+    const char* pLayerName,
+    uint32_t* pPropertyCount,
+    VkExtensionProperties* pProperties) {
+    const InstanceData& data = GetData(physicalDevice);
+
+    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
+        physicalDevice, pLayerName, pPropertyCount, pProperties);
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
+        return result;
+
+    if (!pProperties)
+        return result;
+
+    // map VK_ANDROID_native_buffer to VK_KHR_swapchain
+    for (uint32_t i = 0; i < *pPropertyCount; i++) {
+        auto& prop = pProperties[i];
+
+        if (strcmp(prop.extensionName,
+                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
+            continue;
+
+        memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+               sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
+        prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION;
+    }
+
+    return result;
+}
+
+VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
+                        const VkAllocationCallbacks* pAllocator,
+                        VkInstance* pInstance) {
+    const VkAllocationCallbacks& data_allocator =
+        (pAllocator) ? *pAllocator : GetDefaultAllocator();
+
+    CreateInfoWrapper wrapper(g_hwdevice, *pCreateInfo, data_allocator);
+    VkResult result = wrapper.validate();
+    if (result != VK_SUCCESS)
+        return result;
+
+    InstanceData* data = AllocateInstanceData(data_allocator);
+    if (!data)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    data->hook_extensions |= wrapper.get_hook_extensions();
+    data->hal_extensions |= wrapper.get_hal_extensions();
+
+    // call into the driver
+    VkInstance instance;
+    result = g_hwdevice->CreateInstance(
+        static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
+        &instance);
+    if (result != VK_SUCCESS) {
+        FreeInstanceData(data, data_allocator);
+        return result;
+    }
+
+    // initialize InstanceDriverTable
+    if (!SetData(instance, *data) ||
+        !InitDriverTable(instance, g_hwdevice->GetInstanceProcAddr)) {
+        data->driver.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
+            g_hwdevice->GetInstanceProcAddr(instance, "vkDestroyInstance"));
+        if (data->driver.DestroyInstance)
+            data->driver.DestroyInstance(instance, pAllocator);
+
+        FreeInstanceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    data->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+        g_hwdevice->GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
+    if (!data->get_device_proc_addr) {
+        data->driver.DestroyInstance(instance, pAllocator);
+        FreeInstanceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    *pInstance = instance;
+
+    return VK_SUCCESS;
+}
+
+void DestroyInstance(VkInstance instance,
+                     const VkAllocationCallbacks* pAllocator) {
+    InstanceData& data = GetData(instance);
+    data.driver.DestroyInstance(instance, pAllocator);
+
+    VkAllocationCallbacks local_allocator;
+    if (!pAllocator) {
+        local_allocator = data.allocator;
+        pAllocator = &local_allocator;
+    }
+
+    FreeInstanceData(&data, *pAllocator);
+}
+
+VkResult CreateDevice(VkPhysicalDevice physicalDevice,
+                      const VkDeviceCreateInfo* pCreateInfo,
+                      const VkAllocationCallbacks* pAllocator,
+                      VkDevice* pDevice) {
+    const InstanceData& instance_data = GetData(physicalDevice);
+    const VkAllocationCallbacks& data_allocator =
+        (pAllocator) ? *pAllocator : instance_data.allocator;
+
+    CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
+    VkResult result = wrapper.validate();
+    if (result != VK_SUCCESS)
+        return result;
+
+    DeviceData* data = AllocateDeviceData(data_allocator);
+    if (!data)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    data->hook_extensions |= wrapper.get_hook_extensions();
+    data->hal_extensions |= wrapper.get_hal_extensions();
+
+    // call into the driver
+    VkDevice dev;
+    result = instance_data.driver.CreateDevice(
+        physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
+        pAllocator, &dev);
+    if (result != VK_SUCCESS) {
+        FreeDeviceData(data, data_allocator);
+        return result;
+    }
+
+    // initialize DeviceDriverTable
+    if (!SetData(dev, *data) ||
+        !InitDriverTable(dev, instance_data.get_device_proc_addr)) {
+        data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
+            instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
+        if (data->driver.DestroyDevice)
+            data->driver.DestroyDevice(dev, pAllocator);
+
+        FreeDeviceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    *pDevice = dev;
+
+    return VK_SUCCESS;
+}
+
+void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+    DeviceData& data = GetData(device);
+    data.driver.DestroyDevice(device, pAllocator);
+
+    VkAllocationCallbacks local_allocator;
+    if (!pAllocator) {
+        local_allocator = data.allocator;
+        pAllocator = &local_allocator;
+    }
+
+    FreeDeviceData(&data, *pAllocator);
+}
+
+VkResult EnumeratePhysicalDevices(VkInstance instance,
+                                  uint32_t* pPhysicalDeviceCount,
+                                  VkPhysicalDevice* pPhysicalDevices) {
+    const auto& data = GetData(instance);
+
+    VkResult result = data.driver.EnumeratePhysicalDevices(
+        instance, pPhysicalDeviceCount, pPhysicalDevices);
+    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) {
+        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++)
+            SetData(pPhysicalDevices[i], data);
+    }
+
+    return result;
+}
+
+void GetDeviceQueue(VkDevice device,
+                    uint32_t queueFamilyIndex,
+                    uint32_t queueIndex,
+                    VkQueue* pQueue) {
+    const auto& data = GetData(device);
+
+    data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
+    SetData(*pQueue, data);
+}
+
+VKAPI_ATTR VkResult
+AllocateCommandBuffers(VkDevice device,
+                       const VkCommandBufferAllocateInfo* pAllocateInfo,
+                       VkCommandBuffer* pCommandBuffers) {
+    const auto& data = GetData(device);
+
+    VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
+                                                         pCommandBuffers);
+    if (result == VK_SUCCESS) {
+        for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
+            SetData(pCommandBuffers[i], data);
+    }
+
+    return result;
+}
+
+}  // namespace driver
+}  // namespace vulkan
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index de9d1c6..22db93f 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -18,6 +18,7 @@
 #define LIBVULKAN_DRIVER_H 1
 
 #include <inttypes.h>
+#include <bitset>
 #include <type_traits>
 #include <log/log.h>
 
@@ -25,6 +26,9 @@
 #include <hardware/hwvulkan.h>
 
 #include "api_gen.h"
+#include "driver_gen.h"
+#include "debug_report.h"
+#include "swapchain.h"
 
 namespace vulkan {
 
@@ -61,15 +65,43 @@
 namespace driver {
 
 struct InstanceData {
+    InstanceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(),
+          allocator(alloc),
+          driver(),
+          get_device_proc_addr(nullptr) {
+        hook_extensions.set(ProcHook::EXTENSION_CORE);
+        hal_extensions.set(ProcHook::EXTENSION_CORE);
+    }
+
     api::InstanceData opaque_api_data;
 
     const VkAllocationCallbacks allocator;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
+
+    InstanceDriverTable driver;
+    PFN_vkGetDeviceProcAddr get_device_proc_addr;
+
+    DebugReportCallbackList debug_report_callbacks;
 };
 
 struct DeviceData {
+    DeviceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(), allocator(alloc), driver() {
+        hook_extensions.set(ProcHook::EXTENSION_CORE);
+        hal_extensions.set(ProcHook::EXTENSION_CORE);
+    }
+
     api::DeviceData opaque_api_data;
 
     const VkAllocationCallbacks allocator;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
+
+    DeviceDriverTable driver;
 };
 
 bool Debuggable();
@@ -80,6 +112,17 @@
 VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName);
 VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName);
 VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+
+VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
+
+VKAPI_ATTR VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
+VKAPI_ATTR void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
+VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);
+VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
+VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
 // clang-format on
 
 template <typename DispatchableType>
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
new file mode 100644
index 0000000..8b816ba
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// WARNING: This file is generated. See ../README.md for instructions.
+
+#include <string.h>
+#include <algorithm>
+#include <log/log.h>
+
+#include "driver.h"
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+// clang-format off
+
+VKAPI_ATTR void disabledDestroySurfaceKHR(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*) {
+    ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed.");
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceCapabilitiesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*) {
+    ALOGE("VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledCreateSwapchainKHR(VkDevice, const VkSwapchainCreateInfoKHR*, const VkAllocationCallbacks*, VkSwapchainKHR*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain) : disabledCreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
+}
+
+VKAPI_ATTR void disabledDestroySwapchainKHR(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed.");
+}
+
+VKAPI_ATTR void checkedDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) {
+    (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? DestroySwapchainKHR(device, swapchain, pAllocator) : disabledDestroySwapchainKHR(device, swapchain, pAllocator);
+}
+
+VKAPI_ATTR VkResult disabledGetSwapchainImagesKHR(VkDevice, VkSwapchainKHR, uint32_t*, VkImage*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages) : disabledGetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+}
+
+VKAPI_ATTR VkResult disabledAcquireNextImageKHR(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex) {
+    return (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) ? AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex) : disabledAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, pImageIndex);
+}
+
+VKAPI_ATTR VkResult disabledQueuePresentKHR(VkQueue, const VkPresentInfoKHR*) {
+    ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult checkedQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo) {
+    return (GetData(queue).hook_extensions[ProcHook::KHR_swapchain]) ? QueuePresentKHR(queue, pPresentInfo) : disabledQueuePresentKHR(queue, pPresentInfo);
+}
+
+VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
+    ALOGE("VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR VkResult disabledCreateDebugReportCallbackEXT(VkInstance, const VkDebugReportCallbackCreateInfoEXT*, const VkAllocationCallbacks*, VkDebugReportCallbackEXT*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkCreateDebugReportCallbackEXT not executed.");
+    return VK_SUCCESS;
+}
+
+VKAPI_ATTR void disabledDestroyDebugReportCallbackEXT(VkInstance, VkDebugReportCallbackEXT, const VkAllocationCallbacks*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkDestroyDebugReportCallbackEXT not executed.");
+}
+
+VKAPI_ATTR void disabledDebugReportMessageEXT(VkInstance, VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char*, const char*) {
+    ALOGE("VK_EXT_debug_report not enabled. vkDebugReportMessageEXT not executed.");
+}
+
+// clang-format on
+
+const ProcHook g_proc_hooks[] = {
+    // clang-format off
+    {
+        "vkAcquireImageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkAcquireNextImageKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(AcquireNextImageKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledAcquireNextImageKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImageKHR),
+    },
+    {
+        "vkAllocateCommandBuffers",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateAndroidSurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_android_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateAndroidSurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkCreateDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDebugReportCallbackEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkCreateDevice",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateInstance",
+        ProcHook::GLOBAL,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateInstance),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateSwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateSwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedCreateSwapchainKHR),
+    },
+    {
+        "vkDebugReportMessageEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DebugReportMessageEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDebugReportMessageEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugReportCallbackEXT),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroyDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDevice",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroyInstance",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroySurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkDestroySwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedDestroySwapchainKHR),
+    },
+    {
+        "vkEnumerateDeviceExtensionProperties",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkEnumerateInstanceExtensionProperties",
+        ProcHook::GLOBAL,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkEnumeratePhysicalDevices",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetDeviceProcAddr",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetDeviceQueue",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetInstanceProcAddr",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceCapabilitiesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceCapabilitiesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceFormatsKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceFormatsKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfacePresentModesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfacePresentModesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceSupportKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceSupportKHR),
+        nullptr,
+    },
+    {
+        "vkGetSwapchainGrallocUsageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkGetSwapchainImagesKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetSwapchainImagesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetSwapchainImagesKHR),
+    },
+    {
+        "vkQueuePresentKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledQueuePresentKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedQueuePresentKHR),
+    },
+    {
+        "vkQueueSignalReleaseImageANDROID",
+        ProcHook::DEVICE,
+        ProcHook::ANDROID_native_buffer,
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    // clang-format on
+};
+
+}  // anonymous
+
+const ProcHook* GetProcHook(const char* name) {
+    const auto& begin = g_proc_hooks;
+    const auto& end =
+        g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+    const auto hook = std::lower_bound(
+        begin, end, name,
+        [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+    return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}
+
+ProcHook::Extension GetProcHookExtension(const char* name) {
+    // clang-format off
+    if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer;
+    if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report;
+    if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
+    if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
+    if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
+    // clang-format on
+    return ProcHook::EXTENSION_UNKNOWN;
+}
+
+#define UNLIKELY(expr) __builtin_expect((expr), 0)
+
+#define INIT_PROC(obj, proc)                                           \
+    do {                                                               \
+        data.driver.proc =                                             \
+            reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \
+        if (UNLIKELY(!data.driver.proc)) {                             \
+            ALOGE("missing " #obj " proc: vk" #proc);                  \
+            success = false;                                           \
+        }                                                              \
+    } while (0)
+
+#define INIT_PROC_EXT(ext, obj, proc)           \
+    do {                                        \
+        if (data.hal_extensions[ProcHook::ext]) \
+            INIT_PROC(obj, proc);               \
+    } while (0)
+
+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) {
+    auto& data = GetData(instance);
+    bool success = true;
+
+    // clang-format off
+    INIT_PROC(instance, DestroyInstance);
+    INIT_PROC(instance, EnumeratePhysicalDevices);
+    INIT_PROC(instance, GetInstanceProcAddr);
+    INIT_PROC(instance, CreateDevice);
+    INIT_PROC(instance, EnumerateDeviceLayerProperties);
+    INIT_PROC(instance, EnumerateDeviceExtensionProperties);
+    INIT_PROC_EXT(EXT_debug_report, instance, CreateDebugReportCallbackEXT);
+    INIT_PROC_EXT(EXT_debug_report, instance, DestroyDebugReportCallbackEXT);
+    INIT_PROC_EXT(EXT_debug_report, instance, DebugReportMessageEXT);
+    // clang-format on
+
+    return success;
+}
+
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc) {
+    auto& data = GetData(dev);
+    bool success = true;
+
+    // clang-format off
+    INIT_PROC(dev, GetDeviceProcAddr);
+    INIT_PROC(dev, DestroyDevice);
+    INIT_PROC(dev, GetDeviceQueue);
+    INIT_PROC(dev, CreateImage);
+    INIT_PROC(dev, DestroyImage);
+    INIT_PROC(dev, AllocateCommandBuffers);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, GetSwapchainGrallocUsageANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, AcquireImageANDROID);
+    INIT_PROC_EXT(ANDROID_native_buffer, dev, QueueSignalReleaseImageANDROID);
+    // clang-format on
+
+    return success;
+}
+
+}  // namespace driver
+}  // namespace vulkan
+
+// clang-format on
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
new file mode 100644
index 0000000..1eb7d79
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// WARNING: This file is generated. See ../README.md for instructions.
+
+#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+
+#include <vulkan/vulkan.h>
+#include <vulkan/vk_android_native_buffer.h>
+
+namespace vulkan {
+namespace driver {
+
+struct ProcHook {
+    enum Type {
+        GLOBAL,
+        INSTANCE,
+        DEVICE,
+    };
+    enum Extension {
+        ANDROID_native_buffer,
+        EXT_debug_report,
+        KHR_android_surface,
+        KHR_surface,
+        KHR_swapchain,
+
+        EXTENSION_CORE,  // valid bit
+        EXTENSION_COUNT,
+        EXTENSION_UNKNOWN,
+    };
+
+    const char* name;
+    Type type;
+    Extension extension;
+
+    PFN_vkVoidFunction proc;
+    PFN_vkVoidFunction disabled_proc;  // nullptr for global hooks
+    PFN_vkVoidFunction checked_proc;   // nullptr for global/instance hooks
+};
+
+struct InstanceDriverTable {
+    // clang-format off
+    PFN_vkDestroyInstance DestroyInstance;
+    PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
+    PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+    PFN_vkCreateDevice CreateDevice;
+    PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;
+    PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
+    PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+    PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
+    PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+    // clang-format on
+};
+
+struct DeviceDriverTable {
+    // clang-format off
+    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
+    PFN_vkDestroyDevice DestroyDevice;
+    PFN_vkGetDeviceQueue GetDeviceQueue;
+    PFN_vkCreateImage CreateImage;
+    PFN_vkDestroyImage DestroyImage;
+    PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
+    PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
+    PFN_vkAcquireImageANDROID AcquireImageANDROID;
+    PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
+    // clang-format on
+};
+
+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+
+bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
+bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
+
+}  // namespace driver
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_DRIVER_TABLE_H
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index aec0fd0..6b53a9a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -16,7 +16,7 @@
 
 // #define LOG_NDEBUG 0
 
-#include "loader.h"
+#include "layers_extensions.h"
 #include <alloca.h>
 #include <dirent.h>
 #include <dlfcn.h>
@@ -28,8 +28,6 @@
 #include <log/log.h>
 #include <vulkan/vulkan_loader_data.h>
 
-using namespace vulkan;
-
 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
 // not a good long-term solution. Having a hard-coded enum of extensions is
 // bad, of course. Representing sets of extensions (requested, supported, etc.)
@@ -50,12 +48,13 @@
 // with a mask saying what kind(s) it is.
 
 namespace vulkan {
+namespace api {
+
 struct Layer {
     VkLayerProperties properties;
     size_t library_idx;
     std::vector<VkExtensionProperties> extensions;
 };
-}  // namespace vulkan
 
 namespace {
 
@@ -341,8 +340,6 @@
 
 }  // anonymous namespace
 
-namespace vulkan {
-
 void DiscoverLayers() {
     if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
         DiscoverLayersInDirectory("/data/local/debug/vulkan");
@@ -425,22 +422,5 @@
                         }) != layer_->extensions.cend();
 }
 
-InstanceExtension InstanceExtensionFromName(const char* name) {
-    if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
-        return kKHR_surface;
-    if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0)
-        return kKHR_android_surface;
-    if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
-        return kEXT_debug_report;
-    return kInstanceExtensionCount;
-}
-
-DeviceExtension DeviceExtensionFromName(const char* name) {
-    if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
-        return kKHR_swapchain;
-    if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0)
-        return kANDROID_native_buffer;
-    return kDeviceExtensionCount;
-}
-
+}  // namespace api
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
new file mode 100644
index 0000000..7e7bfd3
--- /dev/null
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBVULKAN_LAYERS_EXTENSIONS_H
+#define LIBVULKAN_LAYERS_EXTENSIONS_H 1
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace api {
+
+struct Layer;
+class LayerRef {
+   public:
+    LayerRef(Layer* layer);
+    LayerRef(LayerRef&& other);
+    ~LayerRef();
+    LayerRef(const LayerRef&) = delete;
+    LayerRef& operator=(const LayerRef&) = delete;
+
+    const char* GetName() const;
+    uint32_t GetSpecVersion();
+
+    // provides bool-like behavior
+    operator const Layer*() const { return layer_; }
+
+    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
+    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;
+
+    bool SupportsExtension(const char* name) const;
+
+   private:
+    Layer* layer_;
+};
+
+void DiscoverLayers();
+uint32_t EnumerateInstanceLayers(uint32_t count, VkLayerProperties* properties);
+uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties);
+void GetInstanceLayerExtensions(const char* name,
+                                const VkExtensionProperties** properties,
+                                uint32_t* count);
+void GetDeviceLayerExtensions(const char* name,
+                              const VkExtensionProperties** properties,
+                              uint32_t* count);
+LayerRef GetInstanceLayerRef(const char* name);
+LayerRef GetDeviceLayerRef(const char* name);
+
+}  // namespace api
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_LAYERS_EXTENSIONS_H
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
deleted file mode 100644
index 65b09db..0000000
--- a/vulkan/libvulkan/loader.cpp
+++ /dev/null
@@ -1,1045 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// module header
-#include "loader.h"
-#include "driver.h"
-// standard C headers
-#include <dirent.h>
-#include <dlfcn.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-// standard C++ headers
-#include <algorithm>
-#include <mutex>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-#include <vector>
-// platform/library headers
-#include <cutils/properties.h>
-#include <hardware/hwvulkan.h>
-#include <log/log.h>
-#include <vulkan/vulkan_loader_data.h>
-#include <vulkan/vk_layer_interface.h>
-
-// #define ENABLE_ALLOC_CALLSTACKS 1
-#if ENABLE_ALLOC_CALLSTACKS
-#include <utils/CallStack.h>
-#define ALOGD_CALLSTACK(...)                             \
-    do {                                                 \
-        ALOGD(__VA_ARGS__);                              \
-        android::CallStack callstack;                    \
-        callstack.update();                              \
-        callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, "  "); \
-    } while (false)
-#else
-#define ALOGD_CALLSTACK(...) \
-    do {                     \
-    } while (false)
-#endif
-
-using namespace vulkan;
-
-static const uint32_t kMaxPhysicalDevices = 4;
-
-namespace {
-
-// ----------------------------------------------------------------------------
-
-// Standard-library allocator that delegates to VkAllocationCallbacks.
-//
-// TODO(jessehall): This class currently always uses
-// VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE. The scope to use could be a template
-// parameter or a constructor parameter. The former would help catch bugs
-// where we use the wrong scope, e.g. adding a command-scope string to an
-// instance-scope vector. But that might also be pretty annoying to deal with.
-template <class T>
-class CallbackAllocator {
-   public:
-    typedef T value_type;
-
-    CallbackAllocator(const VkAllocationCallbacks* alloc_input)
-        : alloc(alloc_input) {}
-
-    template <class T2>
-    CallbackAllocator(const CallbackAllocator<T2>& other)
-        : alloc(other.alloc) {}
-
-    T* allocate(std::size_t n) {
-        void* mem =
-            alloc->pfnAllocation(alloc->pUserData, n * sizeof(T), alignof(T),
-                                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-        if (!mem)
-            throw std::bad_alloc();
-        return static_cast<T*>(mem);
-    }
-
-    void deallocate(T* array, std::size_t /*n*/) noexcept {
-        alloc->pfnFree(alloc->pUserData, array);
-    }
-
-    const VkAllocationCallbacks* alloc;
-};
-// These are needed in order to move Strings
-template <class T>
-bool operator==(const CallbackAllocator<T>& alloc1,
-                const CallbackAllocator<T>& alloc2) {
-    return alloc1.alloc == alloc2.alloc;
-}
-template <class T>
-bool operator!=(const CallbackAllocator<T>& alloc1,
-                const CallbackAllocator<T>& alloc2) {
-    return !(alloc1 == alloc2);
-}
-
-template <class T>
-using Vector = std::vector<T, CallbackAllocator<T>>;
-
-typedef std::basic_string<char, std::char_traits<char>, CallbackAllocator<char>>
-    String;
-
-// ----------------------------------------------------------------------------
-
-VKAPI_ATTR void* DefaultAllocate(void*,
-                                 size_t size,
-                                 size_t alignment,
-                                 VkSystemAllocationScope) {
-    void* ptr = nullptr;
-    // Vulkan requires 'alignment' to be a power of two, but posix_memalign
-    // additionally requires that it be at least sizeof(void*).
-    int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
-    ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
-                    ret, ptr);
-    return ret == 0 ? ptr : nullptr;
-}
-
-VKAPI_ATTR void* DefaultReallocate(void*,
-                                   void* ptr,
-                                   size_t size,
-                                   size_t alignment,
-                                   VkSystemAllocationScope) {
-    if (size == 0) {
-        free(ptr);
-        return nullptr;
-    }
-
-    // TODO(jessehall): Right now we never shrink allocations; if the new
-    // request is smaller than the existing chunk, we just continue using it.
-    // Right now the loader never reallocs, so this doesn't matter. If that
-    // changes, or if this code is copied into some other project, this should
-    // probably have a heuristic to allocate-copy-free when doing so will save
-    // "enough" space.
-    size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
-    if (size <= old_size)
-        return ptr;
-
-    void* new_ptr = nullptr;
-    if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
-        return nullptr;
-    if (ptr) {
-        memcpy(new_ptr, ptr, std::min(old_size, size));
-        free(ptr);
-    }
-    return new_ptr;
-}
-
-VKAPI_ATTR void DefaultFree(void*, void* ptr) {
-    ALOGD_CALLSTACK("Free: %p", ptr);
-    free(ptr);
-}
-
-const VkAllocationCallbacks kDefaultAllocCallbacks = {
-    .pUserData = nullptr,
-    .pfnAllocation = DefaultAllocate,
-    .pfnReallocation = DefaultReallocate,
-    .pfnFree = DefaultFree,
-};
-
-// ----------------------------------------------------------------------------
-// Global Data and Initialization
-
-hwvulkan_device_t* g_hwdevice = nullptr;
-InstanceExtensionSet g_driver_instance_extensions;
-
-void LoadVulkanHAL() {
-    static const hwvulkan_module_t* module;
-    int result =
-        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
-    if (result != 0) {
-        ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result);
-        return;
-    }
-    result = module->common.methods->open(
-        &module->common, HWVULKAN_DEVICE_0,
-        reinterpret_cast<hw_device_t**>(&g_hwdevice));
-    if (result != 0) {
-        ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result),
-              result);
-        module = nullptr;
-        return;
-    }
-
-    VkResult vkresult;
-    uint32_t count;
-    if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties(
-             nullptr, &count, nullptr)) != VK_SUCCESS) {
-        ALOGE("driver EnumerateInstanceExtensionProperties failed: %d",
-              vkresult);
-        g_hwdevice->common.close(&g_hwdevice->common);
-        g_hwdevice = nullptr;
-        module = nullptr;
-        return;
-    }
-    VkExtensionProperties* extensions = static_cast<VkExtensionProperties*>(
-        alloca(count * sizeof(VkExtensionProperties)));
-    if ((vkresult = g_hwdevice->EnumerateInstanceExtensionProperties(
-             nullptr, &count, extensions)) != VK_SUCCESS) {
-        ALOGE("driver EnumerateInstanceExtensionProperties failed: %d",
-              vkresult);
-        g_hwdevice->common.close(&g_hwdevice->common);
-        g_hwdevice = nullptr;
-        module = nullptr;
-        return;
-    }
-    ALOGV_IF(count > 0, "Driver-supported instance extensions:");
-    for (uint32_t i = 0; i < count; i++) {
-        ALOGV("  %s (v%u)", extensions[i].extensionName,
-              extensions[i].specVersion);
-        InstanceExtension id =
-            InstanceExtensionFromName(extensions[i].extensionName);
-        if (id != kInstanceExtensionCount)
-            g_driver_instance_extensions.set(id);
-    }
-    // Ignore driver attempts to support loader extensions
-    g_driver_instance_extensions.reset(kKHR_surface);
-    g_driver_instance_extensions.reset(kKHR_android_surface);
-}
-
-// -----------------------------------------------------------------------------
-
-struct Instance {
-    Instance(const VkAllocationCallbacks* alloc_callbacks)
-        : base{{}, *alloc_callbacks},
-          alloc(&base.allocator),
-          num_physical_devices(0) {
-        memset(physical_devices, 0, sizeof(physical_devices));
-        enabled_extensions.reset();
-        memset(&drv.dispatch, 0, sizeof(drv.dispatch));
-    }
-
-    ~Instance() {}
-
-    driver::InstanceData base;
-
-    const VkAllocationCallbacks* alloc;
-    uint32_t num_physical_devices;
-    VkPhysicalDevice physical_devices_top[kMaxPhysicalDevices];
-    VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
-    DeviceExtensionSet physical_device_driver_extensions[kMaxPhysicalDevices];
-
-    DebugReportCallbackList debug_report_callbacks;
-    InstanceExtensionSet enabled_extensions;
-
-    struct {
-        DriverDispatchTable dispatch;
-    } drv;  // may eventually be an array
-};
-
-struct Device {
-    Device(Instance* instance_)
-        : base{{}, *instance_->alloc}, instance(instance_) {
-        enabled_extensions.reset();
-    }
-
-    driver::DeviceData base;
-
-    Instance* instance;
-    PFN_vkGetDeviceProcAddr get_device_proc_addr;
-    DeviceExtensionSet enabled_extensions;
-};
-
-template <typename THandle>
-struct HandleTraits {};
-template <>
-struct HandleTraits<VkInstance> {
-    typedef Instance LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkPhysicalDevice> {
-    typedef Instance LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkDevice> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkQueue> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkCommandBuffer> {
-    typedef Device LoaderObjectType;
-};
-
-template <typename THandle>
-typename HandleTraits<THandle>::LoaderObjectType& GetDispatchParent(
-    THandle handle) {
-    // TODO(jessehall): Make Instance and Device POD types (by removing the
-    // non-default constructors), so that offsetof is actually legal to use.
-    // The specific case we're using here is safe in gcc/clang (and probably
-    // most other C++ compilers), but isn't guaranteed by C++.
-    typedef typename HandleTraits<THandle>::LoaderObjectType ObjectType;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Winvalid-offsetof"
-    const size_t kBaseOffset = offsetof(ObjectType, base);
-#pragma clang diagnostic pop
-
-    const auto& base = driver::GetData(handle);
-    uintptr_t base_addr = reinterpret_cast<uintptr_t>(&base);
-    uintptr_t object_addr = base_addr - kBaseOffset;
-    return *reinterpret_cast<ObjectType*>(object_addr);
-}
-
-// -----------------------------------------------------------------------------
-
-void DestroyDevice(Device* device, VkDevice vkdevice) {
-    const auto& instance = *device->instance;
-
-    if (vkdevice != VK_NULL_HANDLE)
-        instance.drv.dispatch.DestroyDevice(vkdevice, instance.alloc);
-
-    device->~Device();
-    instance.alloc->pfnFree(instance.alloc->pUserData, device);
-}
-
-/*
- * This function will return the pNext pointer of any
- * CreateInfo extensions that are not loader extensions.
- * This is used to skip past the loader extensions prepended
- * to the list during CreateInstance and CreateDevice.
- */
-void* StripCreateExtensions(const void* pNext) {
-    VkLayerInstanceCreateInfo* create_info =
-        const_cast<VkLayerInstanceCreateInfo*>(
-            static_cast<const VkLayerInstanceCreateInfo*>(pNext));
-
-    while (
-        create_info &&
-        (create_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
-         create_info->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)) {
-        create_info = const_cast<VkLayerInstanceCreateInfo*>(
-            static_cast<const VkLayerInstanceCreateInfo*>(create_info->pNext));
-    }
-
-    return create_info;
-}
-
-// Clean up and deallocate an Instance; called from both the failure paths in
-// CreateInstance_Top as well as from DestroyInstance_Top. This function does
-// not call down the dispatch chain; that should be done before calling this
-// function, iff the lower vkCreateInstance call has been made and returned
-// successfully.
-void DestroyInstance(Instance* instance,
-                     const VkAllocationCallbacks* allocator,
-                     VkInstance vkinstance) {
-    if (vkinstance != VK_NULL_HANDLE && instance->drv.dispatch.DestroyInstance)
-        instance->drv.dispatch.DestroyInstance(vkinstance, allocator);
-
-    instance->~Instance();
-    allocator->pfnFree(allocator->pUserData, instance);
-}
-
-}  // anonymous namespace
-
-namespace vulkan {
-
-// -----------------------------------------------------------------------------
-// "Bottom" functions. These are called at the end of the instance dispatch
-// chain.
-
-VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info,
-                               const VkAllocationCallbacks* allocator,
-                               VkInstance* vkinstance) {
-    VkResult result;
-
-    if (!allocator)
-        allocator = &kDefaultAllocCallbacks;
-
-    void* instance_mem = allocator->pfnAllocation(
-        allocator->pUserData, sizeof(Instance), alignof(Instance),
-        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
-    if (!instance_mem)
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    Instance& instance = *new (instance_mem) Instance(allocator);
-
-    // Check that all enabled extensions are supported
-    uint32_t num_driver_extensions = 0;
-    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-        const char* name = create_info->ppEnabledExtensionNames[i];
-        InstanceExtension id = InstanceExtensionFromName(name);
-        if (id != kInstanceExtensionCount) {
-            if (g_driver_instance_extensions[id]) {
-                num_driver_extensions++;
-                instance.enabled_extensions.set(id);
-                continue;
-            }
-            if (id == kKHR_surface || id == kKHR_android_surface) {
-                instance.enabled_extensions.set(id);
-                continue;
-            }
-            // The loader natively supports debug report.
-            if (id == kEXT_debug_report) {
-                continue;
-            }
-        }
-    }
-
-    VkInstanceCreateInfo driver_create_info = *create_info;
-    driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
-    driver_create_info.enabledLayerCount = 0;
-    driver_create_info.ppEnabledLayerNames = nullptr;
-    driver_create_info.enabledExtensionCount = 0;
-    driver_create_info.ppEnabledExtensionNames = nullptr;
-    if (num_driver_extensions > 0) {
-        const char** names = static_cast<const char**>(
-            alloca(num_driver_extensions * sizeof(char*)));
-        for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-            const char* name = create_info->ppEnabledExtensionNames[i];
-            InstanceExtension id = InstanceExtensionFromName(name);
-            if (id != kInstanceExtensionCount) {
-                if (g_driver_instance_extensions[id]) {
-                    names[driver_create_info.enabledExtensionCount++] = name;
-                    continue;
-                }
-            }
-        }
-        driver_create_info.ppEnabledExtensionNames = names;
-        ALOG_ASSERT(
-            driver_create_info.enabledExtensionCount == num_driver_extensions,
-            "counted enabled driver instance extensions twice and got "
-            "different answers!");
-    }
-
-    VkInstance drv_instance;
-    result = g_hwdevice->CreateInstance(&driver_create_info, instance.alloc,
-                                        &drv_instance);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, VK_NULL_HANDLE);
-        return result;
-    }
-
-    if (!driver::SetData(drv_instance, instance.base)) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    if (!LoadDriverDispatchTable(drv_instance, g_hwdevice->GetInstanceProcAddr,
-                                 instance.enabled_extensions,
-                                 instance.drv.dispatch)) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    uint32_t num_physical_devices = 0;
-    result = instance.drv.dispatch.EnumeratePhysicalDevices(
-        drv_instance, &num_physical_devices, nullptr);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-    num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices);
-    result = instance.drv.dispatch.EnumeratePhysicalDevices(
-        drv_instance, &num_physical_devices, instance.physical_devices);
-    if (result != VK_SUCCESS) {
-        DestroyInstance(&instance, allocator, drv_instance);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    Vector<VkExtensionProperties> extensions(
-        Vector<VkExtensionProperties>::allocator_type(instance.alloc));
-    for (uint32_t i = 0; i < num_physical_devices; i++) {
-        if (!driver::SetData(instance.physical_devices[i], instance.base)) {
-            DestroyInstance(&instance, allocator, drv_instance);
-            return VK_ERROR_INITIALIZATION_FAILED;
-        }
-
-        uint32_t count;
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
-                 instance.physical_devices[i], nullptr, &count, nullptr)) !=
-            VK_SUCCESS) {
-            ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
-                  result);
-            continue;
-        }
-        try {
-            extensions.resize(count);
-        } catch (std::bad_alloc&) {
-            ALOGE("instance creation failed: out of memory");
-            DestroyInstance(&instance, allocator, drv_instance);
-            return VK_ERROR_OUT_OF_HOST_MEMORY;
-        }
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
-                 instance.physical_devices[i], nullptr, &count,
-                 extensions.data())) != VK_SUCCESS) {
-            ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
-                  result);
-            continue;
-        }
-        ALOGV_IF(count > 0, "driver gpu[%u] supports extensions:", i);
-        for (const auto& extension : extensions) {
-            ALOGV("  %s (v%u)", extension.extensionName, extension.specVersion);
-            DeviceExtension id =
-                DeviceExtensionFromName(extension.extensionName);
-            if (id == kDeviceExtensionCount) {
-                ALOGW("driver gpu[%u] extension '%s' unknown to loader", i,
-                      extension.extensionName);
-            } else {
-                instance.physical_device_driver_extensions[i].set(id);
-            }
-        }
-        // Ignore driver attempts to support loader extensions
-        instance.physical_device_driver_extensions[i].reset(kKHR_swapchain);
-    }
-    instance.num_physical_devices = num_physical_devices;
-
-    *vkinstance = drv_instance;
-
-    return VK_SUCCESS;
-}
-
-VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance,
-                                          const VkAndroidSurfaceCreateInfoKHR*,
-                                          const VkAllocationCallbacks*,
-                                          VkSurfaceKHR*) {
-    ALOGE(
-        "VK_KHR_android_surface not enabled. vkCreateAndroidSurfaceKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-void DestroySurfaceKHR_Disabled(VkInstance,
-                                VkSurfaceKHR,
-                                const VkAllocationCallbacks*) {
-    ALOGE("VK_KHR_surface not enabled. vkDestroySurfaceKHR not executed.");
-}
-
-VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice,
-                                                     uint32_t,
-                                                     VkSurfaceKHR,
-                                                     VkBool32*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceSupportKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(
-    VkPhysicalDevice,
-    VkSurfaceKHR,
-    VkSurfaceCapabilitiesKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceapabilitiesKHR "
-        "not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice,
-                                                     VkSurfaceKHR,
-                                                     uint32_t*,
-                                                     VkSurfaceFormatKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfaceFormatsKHR not "
-        "executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice,
-                                                          VkSurfaceKHR,
-                                                          uint32_t*,
-                                                          VkPresentModeKHR*) {
-    ALOGE(
-        "VK_KHR_surface not enabled. vkGetPhysicalDeviceSurfacePresentModesKHR "
-        "not executed.");
-
-    return VK_SUCCESS;
-}
-
-PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance vkinstance,
-                                              const char* name) {
-    PFN_vkVoidFunction pfn;
-
-    if (vkinstance) {
-        Instance& instance = GetDispatchParent(vkinstance);
-        if (!instance.enabled_extensions[kKHR_android_surface]) {
-            // KHR_android_surface is not enabled, use error stubs instead
-            if (strcmp(name, "vkCreateAndroidSurfaceKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    CreateAndroidSurfaceKHR_Disabled);
-            }
-        }
-        if (!instance.enabled_extensions[kKHR_surface]) {
-            // KHR_surface is not enabled, use error stubs instead
-            if (strcmp(name, "vkDestroySurfaceKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    DestroySurfaceKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceSupportKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceSupportKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") ==
-                0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfaceFormatsKHR") == 0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfaceFormatsKHR_Disabled);
-            }
-            if (strcmp(name, "vkGetPhysicalDeviceSurfacePresentModesKHR") ==
-                0) {
-                return reinterpret_cast<PFN_vkVoidFunction>(
-                    GetPhysicalDeviceSurfacePresentModesKHR_Disabled);
-            }
-        }
-    }
-    if ((pfn = GetLoaderBottomProcAddr(name)))
-        return pfn;
-    return g_hwdevice->GetInstanceProcAddr(vkinstance, name);
-}
-
-VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance,
-                                         uint32_t* pdev_count,
-                                         VkPhysicalDevice* pdevs) {
-    Instance& instance = GetDispatchParent(vkinstance);
-    uint32_t count = instance.num_physical_devices;
-    if (pdevs) {
-        count = std::min(count, *pdev_count);
-        std::copy(instance.physical_devices, instance.physical_devices + count,
-                  pdevs);
-    }
-    *pdev_count = count;
-    return VK_SUCCESS;
-}
-
-void GetPhysicalDeviceProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkPhysicalDeviceProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceProperties(
-        pdev, properties);
-}
-
-void GetPhysicalDeviceFeatures_Bottom(VkPhysicalDevice pdev,
-                                      VkPhysicalDeviceFeatures* features) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFeatures(pdev,
-                                                                   features);
-}
-
-void GetPhysicalDeviceMemoryProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkPhysicalDeviceMemoryProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceMemoryProperties(
-        pdev, properties);
-}
-
-void GetPhysicalDeviceQueueFamilyProperties_Bottom(
-    VkPhysicalDevice pdev,
-    uint32_t* pCount,
-    VkQueueFamilyProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceQueueFamilyProperties(
-        pdev, pCount, properties);
-}
-
-void GetPhysicalDeviceFormatProperties_Bottom(VkPhysicalDevice pdev,
-                                              VkFormat format,
-                                              VkFormatProperties* properties) {
-    GetDispatchParent(pdev).drv.dispatch.GetPhysicalDeviceFormatProperties(
-        pdev, format, properties);
-}
-
-VkResult GetPhysicalDeviceImageFormatProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkFormat format,
-    VkImageType type,
-    VkImageTiling tiling,
-    VkImageUsageFlags usage,
-    VkImageCreateFlags flags,
-    VkImageFormatProperties* properties) {
-    return GetDispatchParent(pdev)
-        .drv.dispatch.GetPhysicalDeviceImageFormatProperties(
-            pdev, format, type, tiling, usage, flags, properties);
-}
-
-void GetPhysicalDeviceSparseImageFormatProperties_Bottom(
-    VkPhysicalDevice pdev,
-    VkFormat format,
-    VkImageType type,
-    VkSampleCountFlagBits samples,
-    VkImageUsageFlags usage,
-    VkImageTiling tiling,
-    uint32_t* properties_count,
-    VkSparseImageFormatProperties* properties) {
-    GetDispatchParent(pdev)
-        .drv.dispatch.GetPhysicalDeviceSparseImageFormatProperties(
-            pdev, format, type, samples, usage, tiling, properties_count,
-            properties);
-}
-
-VKAPI_ATTR
-VkResult EnumerateDeviceExtensionProperties_Bottom(
-    VkPhysicalDevice pdev,
-    const char* layer_name,
-    uint32_t* properties_count,
-    VkExtensionProperties* properties) {
-    (void)layer_name;
-
-    Instance& instance = GetDispatchParent(pdev);
-
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != pdev)
-        gpu_idx++;
-    const DeviceExtensionSet driver_extensions =
-        instance.physical_device_driver_extensions[gpu_idx];
-
-    // We only support VK_KHR_swapchain if the GPU supports
-    // VK_ANDROID_native_buffer
-    VkExtensionProperties* available = static_cast<VkExtensionProperties*>(
-        alloca(kDeviceExtensionCount * sizeof(VkExtensionProperties)));
-    uint32_t num_extensions = 0;
-    if (driver_extensions[kANDROID_native_buffer]) {
-        available[num_extensions++] = VkExtensionProperties{
-            VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_SPEC_VERSION};
-    }
-
-    if (!properties || *properties_count > num_extensions)
-        *properties_count = num_extensions;
-    if (properties)
-        std::copy(available, available + *properties_count, properties);
-
-    return *properties_count < num_extensions ? VK_INCOMPLETE : VK_SUCCESS;
-}
-
-// This is a no-op, the Top function returns the aggregate layer property
-// data. This is to keep the dispatch generator happy.
-VKAPI_ATTR
-VkResult EnumerateDeviceLayerProperties_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    uint32_t* /*properties_count*/,
-    VkLayerProperties* /*properties*/) {
-    return VK_SUCCESS;
-}
-
-VKAPI_ATTR
-VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
-                             const VkDeviceCreateInfo* create_info,
-                             const VkAllocationCallbacks* allocator,
-                             VkDevice* device_out) {
-    Instance& instance = GetDispatchParent(gpu);
-
-    // FIXME(jessehall): We don't have good conventions or infrastructure yet to
-    // do better than just using the instance allocator and scope for
-    // everything. See b/26732122.
-    if (true /*!allocator*/)
-        allocator = instance.alloc;
-
-    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
-                                         alignof(Device),
-                                         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
-    if (!mem)
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    Device* device = new (mem) Device(&instance);
-
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != gpu)
-        gpu_idx++;
-
-    VkDeviceCreateInfo driver_create_info = *create_info;
-    driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
-    driver_create_info.enabledLayerCount = 0;
-    driver_create_info.ppEnabledLayerNames = nullptr;
-
-    uint32_t num_driver_extensions = 0;
-    const char** driver_extensions = static_cast<const char**>(
-        alloca(create_info->enabledExtensionCount * sizeof(const char*)));
-    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-        const char* name = create_info->ppEnabledExtensionNames[i];
-        DeviceExtension id = DeviceExtensionFromName(name);
-        if (id != kDeviceExtensionCount) {
-            if (instance.physical_device_driver_extensions[gpu_idx][id]) {
-                driver_extensions[num_driver_extensions++] = name;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-            // Add the VK_ANDROID_native_buffer extension to the list iff
-            // the VK_KHR_swapchain extension was requested
-            if (id == kKHR_swapchain &&
-                instance.physical_device_driver_extensions
-                    [gpu_idx][kANDROID_native_buffer]) {
-                driver_extensions[num_driver_extensions++] =
-                    VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-        }
-    }
-
-    driver_create_info.enabledExtensionCount = num_driver_extensions;
-    driver_create_info.ppEnabledExtensionNames = driver_extensions;
-    VkDevice drv_device;
-    VkResult result = instance.drv.dispatch.CreateDevice(
-        gpu, &driver_create_info, allocator, &drv_device);
-    if (result != VK_SUCCESS) {
-        DestroyDevice(device, VK_NULL_HANDLE);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    if (!driver::SetData(drv_device, device->base)) {
-        DestroyDevice(device, drv_device);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    device->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-        instance.drv.dispatch.GetDeviceProcAddr(drv_device,
-                                                "vkGetDeviceProcAddr"));
-    *device_out = drv_device;
-    return VK_SUCCESS;
-}
-
-void DestroyInstance_Bottom(VkInstance vkinstance,
-                            const VkAllocationCallbacks* allocator) {
-    Instance& instance = GetDispatchParent(vkinstance);
-
-    VkAllocationCallbacks local_allocator;
-    if (!allocator) {
-        local_allocator = *instance.alloc;
-        allocator = &local_allocator;
-    }
-
-    DestroyInstance(&instance, allocator, vkinstance);
-}
-
-VkResult CreateSwapchainKHR_Disabled(VkDevice,
-                                     const VkSwapchainCreateInfoKHR*,
-                                     const VkAllocationCallbacks*,
-                                     VkSwapchainKHR*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkCreateSwapchainKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-void DestroySwapchainKHR_Disabled(VkDevice,
-                                  VkSwapchainKHR,
-                                  const VkAllocationCallbacks*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkDestroySwapchainKHR not executed.");
-}
-
-VkResult GetSwapchainImagesKHR_Disabled(VkDevice,
-                                        VkSwapchainKHR,
-                                        uint32_t*,
-                                        VkImage*) {
-    ALOGE(
-        "VK_KHR_swapchain not enabled. vkGetSwapchainImagesKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult AcquireNextImageKHR_Disabled(VkDevice,
-                                      VkSwapchainKHR,
-                                      uint64_t,
-                                      VkSemaphore,
-                                      VkFence,
-                                      uint32_t*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkAcquireNextImageKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-VkResult QueuePresentKHR_Disabled(VkQueue, const VkPresentInfoKHR*) {
-    ALOGE("VK_KHR_swapchain not enabled. vkQueuePresentKHR not executed.");
-
-    return VK_SUCCESS;
-}
-
-PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice,
-                                            const char* name) {
-    if (strcmp(name, "vkCreateDevice") == 0) {
-        return reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom);
-    }
-
-    Device& device = GetDispatchParent(vkdevice);
-    if (!device.enabled_extensions[kKHR_swapchain]) {
-        if (strcmp(name, "vkCreateSwapchainKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                CreateSwapchainKHR_Disabled);
-        }
-        if (strcmp(name, "vkDestroySwapchainKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                DestroySwapchainKHR_Disabled);
-        }
-        if (strcmp(name, "vkGetSwapchainImagesKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                GetSwapchainImagesKHR_Disabled);
-        }
-        if (strcmp(name, "vkAcquireNextSwapchainImageKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                AcquireNextImageKHR_Disabled);
-        }
-        if (strcmp(name, "vkQueuePresentKHR") == 0) {
-            return reinterpret_cast<PFN_vkVoidFunction>(
-                QueuePresentKHR_Disabled);
-        }
-    }
-
-    // VK_ANDROID_native_buffer should be hidden from applications and layers.
-    // TODO(jessehall): Generate this as part of GetLoaderBottomProcAddr.
-    PFN_vkVoidFunction pfn;
-    if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0 ||
-        strcmp(name, "vkAcquireImageANDROID") == 0 ||
-        strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0) {
-        return nullptr;
-    }
-    if ((pfn = GetLoaderBottomProcAddr(name)))
-        return pfn;
-    return GetDispatchParent(vkdevice).get_device_proc_addr(vkdevice, name);
-}
-
-void DestroyDevice_Bottom(VkDevice vkdevice, const VkAllocationCallbacks*) {
-    DestroyDevice(&GetDispatchParent(vkdevice), vkdevice);
-}
-
-void GetDeviceQueue_Bottom(VkDevice vkdevice,
-                           uint32_t family,
-                           uint32_t index,
-                           VkQueue* queue_out) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
-
-    instance.drv.dispatch.GetDeviceQueue(vkdevice, family, index, queue_out);
-    driver::SetData(*queue_out, device.base);
-}
-
-VkResult AllocateCommandBuffers_Bottom(
-    VkDevice vkdevice,
-    const VkCommandBufferAllocateInfo* alloc_info,
-    VkCommandBuffer* cmdbufs) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
-
-    VkResult result = instance.drv.dispatch.AllocateCommandBuffers(
-        vkdevice, alloc_info, cmdbufs);
-    if (result == VK_SUCCESS) {
-        for (uint32_t i = 0; i < alloc_info->commandBufferCount; i++)
-            driver::SetData(cmdbufs[i], device.base);
-    }
-
-    return result;
-}
-
-// -----------------------------------------------------------------------------
-
-const VkAllocationCallbacks* GetAllocator(VkInstance vkinstance) {
-    return GetDispatchParent(vkinstance).alloc;
-}
-
-const VkAllocationCallbacks* GetAllocator(VkDevice vkdevice) {
-    return GetDispatchParent(vkdevice).instance->alloc;
-}
-
-VkInstance GetDriverInstance(VkInstance instance) {
-    return instance;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkInstance instance) {
-    return GetDispatchParent(instance).drv.dispatch;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkDevice device) {
-    return GetDispatchParent(device).instance->drv.dispatch;
-}
-
-const DriverDispatchTable& GetDriverDispatch(VkQueue queue) {
-    return GetDispatchParent(queue).instance->drv.dispatch;
-}
-
-DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance) {
-    return GetDispatchParent(instance).debug_report_callbacks;
-}
-
-namespace driver {
-
-bool Debuggable() {
-    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
-}
-
-bool OpenHAL() {
-    if (!g_hwdevice)
-        LoadVulkanHAL();
-
-    return (g_hwdevice != nullptr);
-}
-
-const VkAllocationCallbacks& GetDefaultAllocator() {
-    return kDefaultAllocCallbacks;
-}
-
-PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
-    return GetInstanceProcAddr_Bottom(instance, pName);
-}
-
-PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
-    return GetDeviceProcAddr_Bottom(device, pName);
-}
-
-VkResult EnumerateInstanceExtensionProperties(
-    const char* pLayerName,
-    uint32_t* pPropertyCount,
-    VkExtensionProperties* pProperties) {
-    (void)pLayerName;
-
-    VkExtensionProperties* available = static_cast<VkExtensionProperties*>(
-        alloca(kInstanceExtensionCount * sizeof(VkExtensionProperties)));
-    uint32_t num_extensions = 0;
-
-    available[num_extensions++] = VkExtensionProperties{
-        VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION};
-    available[num_extensions++] =
-        VkExtensionProperties{VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
-                              VK_KHR_ANDROID_SURFACE_SPEC_VERSION};
-    if (g_driver_instance_extensions[kEXT_debug_report]) {
-        available[num_extensions++] =
-            VkExtensionProperties{VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
-                                  VK_EXT_DEBUG_REPORT_SPEC_VERSION};
-    }
-
-    if (!pProperties || *pPropertyCount > num_extensions)
-        *pPropertyCount = num_extensions;
-    if (pProperties)
-        std::copy(available, available + *pPropertyCount, pProperties);
-
-    return *pPropertyCount < num_extensions ? VK_INCOMPLETE : VK_SUCCESS;
-}
-
-}  // namespace driver
-
-}  // namespace vulkan
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
deleted file mode 100644
index 0ec08b2..0000000
--- a/vulkan/libvulkan/loader.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LIBVULKAN_LOADER_H
-#define LIBVULKAN_LOADER_H 1
-
-#include <bitset>
-#include "dispatch_gen.h"
-#include "debug_report.h"
-
-namespace vulkan {
-
-enum InstanceExtension {
-    kKHR_surface,
-    kKHR_android_surface,
-    kEXT_debug_report,
-    kInstanceExtensionCount
-};
-typedef std::bitset<kInstanceExtensionCount> InstanceExtensionSet;
-
-enum DeviceExtension {
-    kKHR_swapchain,
-    kANDROID_native_buffer,
-    kDeviceExtensionCount
-};
-typedef std::bitset<kDeviceExtensionCount> DeviceExtensionSet;
-
-// -----------------------------------------------------------------------------
-// dispatch_gen.cpp
-
-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name);
-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch);
-
-// -----------------------------------------------------------------------------
-// loader.cpp
-
-// clang-format off
-VKAPI_ATTR VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance);
-VKAPI_ATTR PFN_vkVoidFunction GetInstanceProcAddr_Bottom(VkInstance, const char* name);
-VKAPI_ATTR VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance, uint32_t* pdev_count, VkPhysicalDevice* pdevs);
-VKAPI_ATTR void GetPhysicalDeviceProperties_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceFeatures_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceFeatures* features);
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties_Bottom(VkPhysicalDevice pdev, VkPhysicalDeviceMemoryProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties_Bottom(VkPhysicalDevice pdev, uint32_t* properties_count, VkQueueFamilyProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkFormatProperties* properties);
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* properties);
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties_Bottom(VkPhysicalDevice pdev, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* properties_count, VkSparseImageFormatProperties* properties);
-VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties_Bottom(VkPhysicalDevice pdev, const char* layer_name, uint32_t* properties_count, VkExtensionProperties* properties);
-VKAPI_ATTR VkResult EnumerateDeviceLayerProperties_Bottom(VkPhysicalDevice pdev, uint32_t* properties_count, VkLayerProperties* properties);
-VKAPI_ATTR VkResult CreateDevice_Bottom(VkPhysicalDevice pdev, const VkDeviceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkDevice* device_out);
-VKAPI_ATTR void DestroyInstance_Bottom(VkInstance vkinstance, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr_Bottom(VkDevice vkdevice, const char* name);
-VKAPI_ATTR void DestroyDevice_Bottom(VkDevice device, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void GetDeviceQueue_Bottom(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
-VKAPI_ATTR VkResult AllocateCommandBuffers_Bottom(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
-// clang-format on
-
-const VkAllocationCallbacks* GetAllocator(VkInstance instance);
-const VkAllocationCallbacks* GetAllocator(VkDevice device);
-VkInstance GetDriverInstance(VkInstance instance);
-const DriverDispatchTable& GetDriverDispatch(VkInstance instance);
-const DriverDispatchTable& GetDriverDispatch(VkDevice device);
-const DriverDispatchTable& GetDriverDispatch(VkQueue queue);
-DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance);
-
-// -----------------------------------------------------------------------------
-// swapchain.cpp
-
-// clang-format off
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR_Bottom(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
-VKAPI_ATTR void DestroySurfaceKHR_Bottom(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
-VKAPI_ATTR VkResult CreateSwapchainKHR_Bottom(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
-VKAPI_ATTR void DestroySwapchainKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetSwapchainImagesKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
-VKAPI_ATTR VkResult AcquireNextImageKHR_Bottom(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
-VKAPI_ATTR VkResult QueuePresentKHR_Bottom(VkQueue queue, const VkPresentInfoKHR* present_info);
-
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR_Disabled(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
-VKAPI_ATTR void DestroySurfaceKHR_Disabled(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR_Disabled(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkSurfaceFormatKHR*);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR_Disabled(VkPhysicalDevice, VkSurfaceKHR, uint32_t*, VkPresentModeKHR*);
-VKAPI_ATTR VkResult CreateSwapchainKHR_Disabled(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
-VKAPI_ATTR void DestroySwapchainKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
-VKAPI_ATTR VkResult GetSwapchainImagesKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
-VKAPI_ATTR VkResult AcquireNextImageKHR_Disabled(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
-VKAPI_ATTR VkResult QueuePresentKHR_Disabled(VkQueue queue, const VkPresentInfoKHR* present_info);
-// clang-format on
-
-// -----------------------------------------------------------------------------
-// layers_extensions.cpp
-
-struct Layer;
-class LayerRef {
-   public:
-    LayerRef(Layer* layer);
-    LayerRef(LayerRef&& other);
-    ~LayerRef();
-    LayerRef(const LayerRef&) = delete;
-    LayerRef& operator=(const LayerRef&) = delete;
-
-    const char* GetName() const;
-    uint32_t GetSpecVersion();
-
-    // provides bool-like behavior
-    operator const Layer*() const { return layer_; }
-
-    PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
-    PFN_vkGetDeviceProcAddr GetGetDeviceProcAddr() const;
-
-    bool SupportsExtension(const char* name) const;
-
-   private:
-    Layer* layer_;
-};
-
-void DiscoverLayers();
-uint32_t EnumerateInstanceLayers(uint32_t count, VkLayerProperties* properties);
-uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties);
-void GetInstanceLayerExtensions(const char* name,
-                                const VkExtensionProperties** properties,
-                                uint32_t* count);
-void GetDeviceLayerExtensions(const char* name,
-                              const VkExtensionProperties** properties,
-                              uint32_t* count);
-LayerRef GetInstanceLayerRef(const char* name);
-LayerRef GetDeviceLayerRef(const char* name);
-
-InstanceExtension InstanceExtensionFromName(const char* name);
-DeviceExtension DeviceExtensionFromName(const char* name);
-
-}  // namespace vulkan
-
-#endif  // LIBVULKAN_LOADER_H
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index ee52857..320a2ac 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -21,14 +21,14 @@
 #include <log/log.h>
 #include <sync/sync.h>
 
-#include "loader.h"
-
-using namespace vulkan;
+#include "driver.h"
 
 // TODO(jessehall): Currently we don't have a good error code for when a native
 // window operation fails. Just returning INITIALIZATION_FAILED for now. Later
 // versions (post SDK 0.9) of the API/extension have a better error code.
 // When updating to that version, audit all error returns.
+namespace vulkan {
+namespace driver {
 
 namespace {
 
@@ -98,9 +98,9 @@
 std::shared_ptr<T> InitSharedPtr(Host host, T* obj) {
     try {
         obj->common.incRef(&obj->common);
-        return std::shared_ptr<T>(
-            obj, NativeBaseDeleter<T>(),
-            VulkanAllocator<T>(*GetAllocator(host), AllocScope<Host>::kScope));
+        return std::shared_ptr<T>(obj, NativeBaseDeleter<T>(),
+                                  VulkanAllocator<T>(GetData(host).allocator,
+                                                     AllocScope<Host>::kScope));
     } catch (std::bad_alloc&) {
         return nullptr;
     }
@@ -223,16 +223,14 @@
 
 }  // anonymous namespace
 
-namespace vulkan {
-
 VKAPI_ATTR
-VkResult CreateAndroidSurfaceKHR_Bottom(
+VkResult CreateAndroidSurfaceKHR(
     VkInstance instance,
     const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
     const VkAllocationCallbacks* allocator,
     VkSurfaceKHR* out_surface) {
     if (!allocator)
-        allocator = GetAllocator(instance);
+        allocator = &GetData(instance).allocator;
     void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface),
                                          alignof(Surface),
                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
@@ -266,30 +264,30 @@
 }
 
 VKAPI_ATTR
-void DestroySurfaceKHR_Bottom(VkInstance instance,
-                              VkSurfaceKHR surface_handle,
-                              const VkAllocationCallbacks* allocator) {
+void DestroySurfaceKHR(VkInstance instance,
+                       VkSurfaceKHR surface_handle,
+                       const VkAllocationCallbacks* allocator) {
     Surface* surface = SurfaceFromHandle(surface_handle);
     if (!surface)
         return;
     native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
     surface->~Surface();
     if (!allocator)
-        allocator = GetAllocator(instance);
+        allocator = &GetData(instance).allocator;
     allocator->pfnFree(allocator->pUserData, surface);
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceSupportKHR_Bottom(VkPhysicalDevice /*pdev*/,
-                                                   uint32_t /*queue_family*/,
-                                                   VkSurfaceKHR /*surface*/,
-                                                   VkBool32* supported) {
+VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
+                                            uint32_t /*queue_family*/,
+                                            VkSurfaceKHR /*surface*/,
+                                            VkBool32* supported) {
     *supported = VK_TRUE;
     return VK_SUCCESS;
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR_Bottom(
+VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(
     VkPhysicalDevice /*pdev*/,
     VkSurfaceKHR surface,
     VkSurfaceCapabilitiesKHR* capabilities) {
@@ -356,11 +354,10 @@
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceFormatsKHR_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    VkSurfaceKHR /*surface*/,
-    uint32_t* count,
-    VkSurfaceFormatKHR* formats) {
+VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
+                                            VkSurfaceKHR /*surface*/,
+                                            uint32_t* count,
+                                            VkSurfaceFormatKHR* formats) {
     // TODO(jessehall): Fill out the set of supported formats. Longer term, add
     // a new gralloc method to query whether a (format, usage) pair is
     // supported, and check that for each gralloc format that corresponds to a
@@ -385,11 +382,10 @@
 }
 
 VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfacePresentModesKHR_Bottom(
-    VkPhysicalDevice /*pdev*/,
-    VkSurfaceKHR /*surface*/,
-    uint32_t* count,
-    VkPresentModeKHR* modes) {
+VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice /*pdev*/,
+                                                 VkSurfaceKHR /*surface*/,
+                                                 uint32_t* count,
+                                                 VkPresentModeKHR* modes) {
     const VkPresentModeKHR kModes[] = {
         VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
     };
@@ -406,15 +402,15 @@
 }
 
 VKAPI_ATTR
-VkResult CreateSwapchainKHR_Bottom(VkDevice device,
-                                   const VkSwapchainCreateInfoKHR* create_info,
-                                   const VkAllocationCallbacks* allocator,
-                                   VkSwapchainKHR* swapchain_handle) {
+VkResult CreateSwapchainKHR(VkDevice device,
+                            const VkSwapchainCreateInfoKHR* create_info,
+                            const VkAllocationCallbacks* allocator,
+                            VkSwapchainKHR* swapchain_handle) {
     int err;
     VkResult result = VK_SUCCESS;
 
     if (!allocator)
-        allocator = GetAllocator(device);
+        allocator = &GetData(device).allocator;
 
     ALOGV_IF(create_info->imageArrayLayers != 1,
              "Swapchain imageArrayLayers (%u) != 1 not supported",
@@ -435,7 +431,7 @@
     // -- Configure the native window --
 
     Surface& surface = *SurfaceFromHandle(create_info->surface);
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+    const auto& dispatch = GetData(device).driver;
 
     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
     switch (create_info->imageFormat) {
@@ -680,10 +676,10 @@
 }
 
 VKAPI_ATTR
-void DestroySwapchainKHR_Bottom(VkDevice device,
-                                VkSwapchainKHR swapchain_handle,
-                                const VkAllocationCallbacks* allocator) {
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+void DestroySwapchainKHR(VkDevice device,
+                         VkSwapchainKHR swapchain_handle,
+                         const VkAllocationCallbacks* allocator) {
+    const auto& dispatch = GetData(device).driver;
     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
     const std::shared_ptr<ANativeWindow>& window = swapchain->surface.window;
 
@@ -701,16 +697,16 @@
     }
 
     if (!allocator)
-        allocator = GetAllocator(device);
+        allocator = &GetData(device).allocator;
     swapchain->~Swapchain();
     allocator->pfnFree(allocator->pUserData, swapchain);
 }
 
 VKAPI_ATTR
-VkResult GetSwapchainImagesKHR_Bottom(VkDevice,
-                                      VkSwapchainKHR swapchain_handle,
-                                      uint32_t* count,
-                                      VkImage* images) {
+VkResult GetSwapchainImagesKHR(VkDevice,
+                               VkSwapchainKHR swapchain_handle,
+                               uint32_t* count,
+                               VkImage* images) {
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     VkResult result = VK_SUCCESS;
     if (images) {
@@ -727,12 +723,12 @@
 }
 
 VKAPI_ATTR
-VkResult AcquireNextImageKHR_Bottom(VkDevice device,
-                                    VkSwapchainKHR swapchain_handle,
-                                    uint64_t timeout,
-                                    VkSemaphore semaphore,
-                                    VkFence vk_fence,
-                                    uint32_t* image_index) {
+VkResult AcquireNextImageKHR(VkDevice device,
+                             VkSwapchainKHR swapchain_handle,
+                             uint64_t timeout,
+                             VkSemaphore semaphore,
+                             VkFence vk_fence,
+                             uint32_t* image_index) {
     Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
     ANativeWindow* window = swapchain.surface.window.get();
     VkResult result;
@@ -776,7 +772,7 @@
         }
     }
 
-    result = GetDriverDispatch(device).AcquireImageANDROID(
+    result = GetData(device).driver.AcquireImageANDROID(
         device, swapchain.images[idx].image, fence_clone, semaphore, vk_fence);
     if (result != VK_SUCCESS) {
         // NOTE: we're relying on AcquireImageANDROID to close fence_clone,
@@ -797,14 +793,13 @@
 }
 
 VKAPI_ATTR
-VkResult QueuePresentKHR_Bottom(VkQueue queue,
-                                const VkPresentInfoKHR* present_info) {
+VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
     ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
              "vkQueuePresentKHR: invalid VkPresentInfoKHR structure type %d",
              present_info->sType);
     ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
 
-    const DriverDispatchTable& dispatch = GetDriverDispatch(queue);
+    const auto& dispatch = GetData(queue).driver;
     VkResult final_result = VK_SUCCESS;
     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
         Swapchain& swapchain =
@@ -857,4 +852,5 @@
     return final_result;
 }
 
+}  // namespace driver
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
new file mode 100644
index 0000000..2c60c49
--- /dev/null
+++ b/vulkan/libvulkan/swapchain.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBVULKAN_SWAPCHAIN_H
+#define LIBVULKAN_SWAPCHAIN_H 1
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace driver {
+
+// clang-format off
+VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
+VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
+VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
+VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);
+VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint32_t* count, VkImage* images);
+VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain_handle, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* image_index);
+VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info);
+// clang-format on
+
+}  // namespace driver
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_SWAPCHAIN_H