vulkan: rework DriverDispatchTable

Generate {Instance,Device}DriverTable from code-generator.tmpl to replace
dispatch.tmpl entirely.  The new code avoids initializing
VK_ANDROID_native_buffer entries when the extension is not enabled.  The
separation of instance and device driver tables also allows us to
initialize the device driver table with vkGetDeviceProcAddr, which is
expected to return more efficient function pointers on properly
implemented HALs.

CreateInstance_Bottom always has a potential resource leak when the
HAL-created instance does not contain HWVULKAN_DISPATCH_MAGIC.
CreateDevice_Bottom now has the same issue.  Both of them will be fixed in
following commits.

Change-Id: If7800ef23098121f1fff643a2c5224c2c9be0711
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 62d1279..7b7e01f 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -42,7 +42,6 @@
 	api.cpp \
 	api_gen.cpp \
 	debug_report.cpp \
-	dispatch_gen.cpp \
 	driver.cpp \
 	driver_gen.cpp \
 	layers_extensions.cpp \
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index f7083c3..23c2717 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -46,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
@@ -56,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
@@ -91,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);
@@ -169,9 +171,32 @@

 {{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

@@ -245,6 +270,42 @@
   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

@@ -254,10 +315,10 @@
 
 {{/*
 ------------------------------------------------------------------------------
-  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" $}}
@@ -266,10 +327,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 {                             \
@@ -280,11 +341,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}}
 
 
@@ -368,6 +424,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.
 ------------------------------------------------------------------------------
@@ -614,6 +683,19 @@
 
 {{/*
 -------------------------------------------------------------------------------
+  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.
 -------------------------------------------------------------------------------
 */}}
@@ -764,6 +846,78 @@
 
 {{/*
 -------------------------------------------------------------------------------
+  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
+
+    {{/* 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.
 -------------------------------------------------------------------------------
 */}}
diff --git a/vulkan/libvulkan/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
deleted file mode 100644
index fd77879..0000000
--- a/vulkan/libvulkan/dispatch.tmpl
+++ /dev/null
@@ -1,326 +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 vulkan {

-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 fa199bd..0000000
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ /dev/null
@@ -1,160 +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 vulkan {
-
-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
index 68ae5c8..d517c72 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -193,7 +193,7 @@
 PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
     const ProcHook* hook = GetProcHook(pName);
     if (!hook)
-        return GetData(device).get_device_proc_addr(device, pName);
+        return GetData(device).driver.GetDeviceProcAddr(device, pName);
 
     if (hook->type != ProcHook::DEVICE) {
         ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 28b0ce6..7af63fa 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -64,7 +64,10 @@
 
 struct InstanceData {
     InstanceData(const VkAllocationCallbacks& alloc)
-        : opaque_api_data(), allocator(alloc) {
+        : opaque_api_data(),
+          allocator(alloc),
+          driver(),
+          get_device_proc_addr(nullptr) {
         hook_extensions.set(ProcHook::EXTENSION_CORE);
         hal_extensions.set(ProcHook::EXTENSION_CORE);
     }
@@ -75,11 +78,14 @@
 
     std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
     std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
+
+    InstanceDriverTable driver;
+    PFN_vkGetDeviceProcAddr get_device_proc_addr;
 };
 
 struct DeviceData {
     DeviceData(const VkAllocationCallbacks& alloc)
-        : opaque_api_data(), allocator(alloc), get_device_proc_addr(nullptr) {
+        : opaque_api_data(), allocator(alloc), driver() {
         hook_extensions.set(ProcHook::EXTENSION_CORE);
         hal_extensions.set(ProcHook::EXTENSION_CORE);
     }
@@ -91,7 +97,7 @@
     std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
     std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions;
 
-    PFN_vkGetDeviceProcAddr get_device_proc_addr;
+    DeviceDriverTable driver;
 };
 
 bool Debuggable();
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index d725df5..87987c8 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -370,6 +370,61 @@
     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, 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
 
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 63dadcb..4226a63 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -52,9 +52,39 @@
     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_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
 
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 8c68efa..3e5ea22 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -147,7 +147,6 @@
           num_physical_devices(0) {
         memset(physical_devices, 0, sizeof(physical_devices));
         enabled_extensions.reset();
-        memset(&drv.dispatch, 0, sizeof(drv.dispatch));
     }
 
     ~Instance() {}
@@ -162,10 +161,6 @@
 
     DebugReportCallbackList debug_report_callbacks;
     InstanceExtensionSet enabled_extensions;
-
-    struct {
-        DriverDispatchTable dispatch;
-    } drv;  // may eventually be an array
 };
 
 struct Device {
@@ -226,8 +221,8 @@
 void DestroyDevice(Device* device, VkDevice vkdevice) {
     const auto& instance = *device->instance;
 
-    if (vkdevice != VK_NULL_HANDLE)
-        instance.drv.dispatch.DestroyDevice(vkdevice, instance.alloc);
+    if (vkdevice != VK_NULL_HANDLE && device->base.driver.DestroyDevice)
+        device->base.driver.DestroyDevice(vkdevice, instance.alloc);
 
     device->~Device();
     instance.alloc->pfnFree(instance.alloc->pUserData, device);
@@ -263,8 +258,8 @@
 void DestroyInstance(Instance* instance,
                      const VkAllocationCallbacks* allocator,
                      VkInstance vkinstance) {
-    if (vkinstance != VK_NULL_HANDLE && instance->drv.dispatch.DestroyInstance)
-        instance->drv.dispatch.DestroyInstance(vkinstance, allocator);
+    if (vkinstance != VK_NULL_HANDLE && instance->base.driver.DestroyInstance)
+        instance->base.driver.DestroyInstance(vkinstance, allocator);
 
     instance->~Instance();
     allocator->pfnFree(allocator->pUserData, instance);
@@ -397,22 +392,30 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    if (!LoadDriverDispatchTable(drv_instance, g_hwdevice->GetInstanceProcAddr,
-                                 instance.enabled_extensions,
-                                 instance.drv.dispatch)) {
+    if (!driver::InitDriverTable(drv_instance,
+                                 g_hwdevice->GetInstanceProcAddr)) {
+        DestroyInstance(&instance, allocator, drv_instance);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
+    instance.base.get_device_proc_addr =
+        reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+            g_hwdevice->GetInstanceProcAddr(drv_instance,
+                                            "vkGetDeviceProcAddr"));
+    if (!instance.base.get_device_proc_addr) {
         DestroyInstance(&instance, allocator, drv_instance);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
     uint32_t num_physical_devices = 0;
-    result = instance.drv.dispatch.EnumeratePhysicalDevices(
+    result = instance.base.driver.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(
+    result = instance.base.driver.EnumeratePhysicalDevices(
         drv_instance, &num_physical_devices, instance.physical_devices);
     if (result != VK_SUCCESS) {
         DestroyInstance(&instance, allocator, drv_instance);
@@ -428,7 +431,7 @@
         }
 
         uint32_t count;
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
+        if ((result = instance.base.driver.EnumerateDeviceExtensionProperties(
                  instance.physical_devices[i], nullptr, &count, nullptr)) !=
             VK_SUCCESS) {
             ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
@@ -442,7 +445,7 @@
             DestroyInstance(&instance, allocator, drv_instance);
             return VK_ERROR_OUT_OF_HOST_MEMORY;
         }
-        if ((result = instance.drv.dispatch.EnumerateDeviceExtensionProperties(
+        if ((result = instance.base.driver.EnumerateDeviceExtensionProperties(
                  instance.physical_devices[i], nullptr, &count,
                  extensions.data())) != VK_SUCCESS) {
             ALOGW("driver EnumerateDeviceExtensionProperties(%u) failed: %d", i,
@@ -596,7 +599,7 @@
     driver_create_info.enabledExtensionCount = num_driver_extensions;
     driver_create_info.ppEnabledExtensionNames = driver_extensions;
     VkDevice drv_device;
-    VkResult result = instance.drv.dispatch.CreateDevice(
+    VkResult result = instance.base.driver.CreateDevice(
         gpu, &driver_create_info, allocator, &drv_device);
     if (result != VK_SUCCESS) {
         DestroyDevice(device, VK_NULL_HANDLE);
@@ -608,10 +611,11 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    device->base.get_device_proc_addr =
-        reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-            instance.drv.dispatch.GetDeviceProcAddr(drv_device,
-                                                    "vkGetDeviceProcAddr"));
+    if (!driver::InitDriverTable(drv_device,
+                                 instance.base.get_device_proc_addr)) {
+        DestroyDevice(device, drv_device);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
 
     *device_out = drv_device;
     return VK_SUCCESS;
@@ -638,25 +642,23 @@
                            uint32_t family,
                            uint32_t index,
                            VkQueue* queue_out) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
+    const auto& data = driver::GetData(vkdevice);
 
-    instance.drv.dispatch.GetDeviceQueue(vkdevice, family, index, queue_out);
-    driver::SetData(*queue_out, device.base);
+    data.driver.GetDeviceQueue(vkdevice, family, index, queue_out);
+    driver::SetData(*queue_out, data);
 }
 
 VkResult AllocateCommandBuffers_Bottom(
     VkDevice vkdevice,
     const VkCommandBufferAllocateInfo* alloc_info,
     VkCommandBuffer* cmdbufs) {
-    const auto& device = GetDispatchParent(vkdevice);
-    const auto& instance = *device.instance;
+    const auto& data = driver::GetData(vkdevice);
 
-    VkResult result = instance.drv.dispatch.AllocateCommandBuffers(
-        vkdevice, alloc_info, cmdbufs);
+    VkResult result =
+        data.driver.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);
+            driver::SetData(cmdbufs[i], data);
     }
 
     return result;
@@ -676,16 +678,16 @@
     return instance;
 }
 
-const DriverDispatchTable& GetDriverDispatch(VkInstance instance) {
-    return GetDispatchParent(instance).drv.dispatch;
+const driver::InstanceDriverTable& GetDriverDispatch(VkInstance instance) {
+    return driver::GetData(instance).driver;
 }
 
-const DriverDispatchTable& GetDriverDispatch(VkDevice device) {
-    return GetDispatchParent(device).instance->drv.dispatch;
+const driver::DeviceDriverTable& GetDriverDispatch(VkDevice device) {
+    return driver::GetData(device).driver;
 }
 
-const DriverDispatchTable& GetDriverDispatch(VkQueue queue) {
-    return GetDispatchParent(queue).instance->drv.dispatch;
+const driver::DeviceDriverTable& GetDriverDispatch(VkQueue queue) {
+    return driver::GetData(queue).driver;
 }
 
 DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance) {
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 15b773d..a2c7e83 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -18,8 +18,9 @@
 #define LIBVULKAN_LOADER_H 1
 
 #include <bitset>
-#include "dispatch_gen.h"
+#include <vulkan/vulkan.h>
 #include "debug_report.h"
+#include "driver.h"
 
 struct hwvulkan_device_t;
 
@@ -41,14 +42,6 @@
 typedef std::bitset<kDeviceExtensionCount> DeviceExtensionSet;
 
 // -----------------------------------------------------------------------------
-// dispatch_gen.cpp
-
-bool LoadDriverDispatchTable(VkInstance instance,
-                             PFN_vkGetInstanceProcAddr get_proc_addr,
-                             const InstanceExtensionSet& extensions,
-                             DriverDispatchTable& dispatch);
-
-// -----------------------------------------------------------------------------
 // loader.cpp
 
 bool InitLoader(hwvulkan_device_t* dev);
@@ -67,9 +60,9 @@
 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);
+const driver::InstanceDriverTable& GetDriverDispatch(VkInstance instance);
+const driver::DeviceDriverTable& GetDriverDispatch(VkDevice device);
+const driver::DeviceDriverTable& GetDriverDispatch(VkQueue queue);
 DebugReportCallbackList& GetDebugReportCallbacks(VkInstance instance);
 
 // -----------------------------------------------------------------------------
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 7f944cf..cc4ae3d 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -436,7 +436,7 @@
     // -- Configure the native window --
 
     Surface& surface = *SurfaceFromHandle(create_info->surface);
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+    const auto& dispatch = GetDriverDispatch(device);
 
     int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
     switch (create_info->imageFormat) {
@@ -684,7 +684,7 @@
 void DestroySwapchainKHR_Bottom(VkDevice device,
                                 VkSwapchainKHR swapchain_handle,
                                 const VkAllocationCallbacks* allocator) {
-    const DriverDispatchTable& dispatch = GetDriverDispatch(device);
+    const auto& dispatch = GetDriverDispatch(device);
     Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
     const std::shared_ptr<ANativeWindow>& window = swapchain->surface.window;
 
@@ -805,7 +805,7 @@
              present_info->sType);
     ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
 
-    const DriverDispatchTable& dispatch = GetDriverDispatch(queue);
+    const auto& dispatch = GetDriverDispatch(queue);
     VkResult final_result = VK_SUCCESS;
     for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
         Swapchain& swapchain =