vulkan: rework driver::Get*ProcAddr

Introduce driver::ProcHook which is a struct to describe an intercepted
function.  Given a function name, GetProcHook returns a ProcHook if the
function is intercepted.  NULL otherwise.

A ProcHook has three function pointers.  ProcHook::proc points to the real
intercepting function.  ProcHook::disabled_proc points to a no-op function
that logs an error.  ProcHook::checked_proc points to a trampoline that
calls either ProcHook::proc or ProcHook::disabled_proc.

For core functions, driver::Get*ProcAddr simply return ProcHook::proc.
For extension functions, driver::Get*ProcAddr return ProcHook::proc when
the extension is known to be enabled.  They return ProcHook::disabled_proc
when the extension is known to be disabled.  Finally, they return
ProcHook::checked_proc when they do not know if the extension is enabled
or not.

All ProcHooks as well as their disabled_proc/checked_proc are generated in
driver_gen.cpp.  This allows us to get rid of all hand-written "_Disabled"
functions, all no-op "_Bottom" functions, and special cases for
VK_ANDROID_native_buffer.  The reworked driver::Get*ProcAddr also detects
more applications' errors and logs them.

Change-Id: I8e6f476f450688b5547fd75243c66cb603c516b5
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index 665d45e..62d1279 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -44,6 +44,7 @@
 	debug_report.cpp \
 	dispatch_gen.cpp \
 	driver.cpp \
+	driver_gen.cpp \
 	layers_extensions.cpp \
 	loader.cpp \
 	swapchain.cpp \
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 7ebe983..f7083c3 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"}}
 
 {{/*
 -------------------------------------------------------------------------------
@@ -147,6 +149,110 @@
 
 
 {{/*
+-------------------------------------------------------------------------------
+  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"}}

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

+»} // 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"
+#include "loader.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;
+}

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

+// clang-format on
+¶{{end}}
+
+
+{{/*
 ------------------------------------------------------------------------------
   Emits a declaration of a dispatch table entry.
 ------------------------------------------------------------------------------
@@ -386,6 +492,277 @@
 
 
 {{/*
+------------------------------------------------------------------------------
+  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 "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
+
+    {{/* 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
+
+    {{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 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}}_Bottom({{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,
+    {{if eq $.Name "vkEnumerateInstanceExtensionProperties"}}
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+    {{else}}
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+    {{end}}
+    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}}_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        nullptr,
+      {{end}}
+    {{else}}
+      ProcHook::EXTENSION_CORE,
+
+      {{if eq $.Name "vkGetInstanceProcAddr"}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      {{else}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+      {{end}}
+      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}}_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabled{{$base}}),
+        reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
+      {{end}}
+    {{else}}
+        ProcHook::EXTENSION_CORE,
+
+        {{if eq $.Name "vkGetDeviceProcAddr"}}
+          reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+        {{else}}
+          reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
+        {{end}}
+        nullptr,
+        nullptr,
+    {{end}}
+  },
+{{end}}
+
+
+{{/*
 -------------------------------------------------------------------------------
   Emits a function/extension name without the "vk"/"VK_" prefix.
 -------------------------------------------------------------------------------
@@ -517,3 +894,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/dispatch.tmpl b/vulkan/libvulkan/dispatch.tmpl
index 67ead4a..fd77879 100644
--- a/vulkan/libvulkan/dispatch.tmpl
+++ b/vulkan/libvulkan/dispatch.tmpl
@@ -118,47 +118,8 @@

 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,
diff --git a/vulkan/libvulkan/dispatch_gen.cpp b/vulkan/libvulkan/dispatch_gen.cpp
index eacf1a1..fa199bd 100644
--- a/vulkan/libvulkan/dispatch_gen.cpp
+++ b/vulkan/libvulkan/dispatch_gen.cpp
@@ -24,74 +24,8 @@
 
 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,
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 4acc867..68ae5c8 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -143,5 +143,67 @@
     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).get_device_proc_addr(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;
+}
+
 }  // namespace driver
 }  // namespace vulkan
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index de9d1c6..28b0ce6 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,7 @@
 #include <hardware/hwvulkan.h>
 
 #include "api_gen.h"
+#include "driver_gen.h"
 
 namespace vulkan {
 
@@ -61,15 +63,35 @@
 namespace driver {
 
 struct InstanceData {
+    InstanceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(), allocator(alloc) {
+        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;
 };
 
 struct DeviceData {
+    DeviceData(const VkAllocationCallbacks& alloc)
+        : opaque_api_data(), allocator(alloc), get_device_proc_addr(nullptr) {
+        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;
+
+    PFN_vkGetDeviceProcAddr get_device_proc_addr;
 };
 
 bool Debuggable();
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
new file mode 100644
index 0000000..d725df5
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -0,0 +1,376 @@
+/*
+ * 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"
+#include "loader.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_Bottom(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_Bottom(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_Bottom(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_Bottom(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_Bottom(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_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledAcquireNextImageKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedAcquireNextImageKHR),
+    },
+    {
+        "vkAllocateCommandBuffers",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers_Bottom),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateAndroidSurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_android_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateAndroidSurfaceKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateAndroidSurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkCreateDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDebugReportCallbackEXT_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkCreateDevice",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateInstance",
+        ProcHook::GLOBAL,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateInstance_Bottom),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkCreateSwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(CreateSwapchainKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledCreateSwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedCreateSwapchainKHR),
+    },
+    {
+        "vkDebugReportMessageEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DebugReportMessageEXT_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDebugReportMessageEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDebugReportCallbackEXT",
+        ProcHook::INSTANCE,
+        ProcHook::EXT_debug_report,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugReportCallbackEXT_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroyDebugReportCallbackEXT),
+        nullptr,
+    },
+    {
+        "vkDestroyDevice",
+        ProcHook::DEVICE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice_Bottom),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroyInstance",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance_Bottom),
+        nullptr,
+        nullptr,
+    },
+    {
+        "vkDestroySurfaceKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySurfaceKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySurfaceKHR),
+        nullptr,
+    },
+    {
+        "vkDestroySwapchainKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(DestroySwapchainKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledDestroySwapchainKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedDestroySwapchainKHR),
+    },
+    {
+        "vkEnumerateDeviceExtensionProperties",
+        ProcHook::INSTANCE,
+        ProcHook::EXTENSION_CORE,
+        reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties_Bottom),
+        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_Bottom),
+        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_Bottom),
+        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_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceCapabilitiesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceFormatsKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceFormatsKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfaceFormatsKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfacePresentModesKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfacePresentModesKHR_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetPhysicalDeviceSurfacePresentModesKHR),
+        nullptr,
+    },
+    {
+        "vkGetPhysicalDeviceSurfaceSupportKHR",
+        ProcHook::INSTANCE,
+        ProcHook::KHR_surface,
+        reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSurfaceSupportKHR_Bottom),
+        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_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(disabledGetSwapchainImagesKHR),
+        reinterpret_cast<PFN_vkVoidFunction>(checkedGetSwapchainImagesKHR),
+    },
+    {
+        "vkQueuePresentKHR",
+        ProcHook::DEVICE,
+        ProcHook::KHR_swapchain,
+        reinterpret_cast<PFN_vkVoidFunction>(QueuePresentKHR_Bottom),
+        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;
+}
+
+}  // 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..63dadcb
--- /dev/null
+++ b/vulkan/libvulkan/driver_gen.h
@@ -0,0 +1,61 @@
+/*
+ * 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
+};
+
+const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+
+}  // namespace driver
+}  // namespace vulkan
+
+#endif  // LIBVULKAN_DRIVER_TABLE_H
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 2d48fda..8c68efa 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -142,7 +142,7 @@
 
 struct Instance {
     Instance(const VkAllocationCallbacks* alloc_callbacks)
-        : base{{}, *alloc_callbacks},
+        : base(*alloc_callbacks),
           alloc(&base.allocator),
           num_physical_devices(0) {
         memset(physical_devices, 0, sizeof(physical_devices));
@@ -169,15 +169,13 @@
 };
 
 struct Device {
-    Device(Instance* instance_)
-        : base{{}, *instance_->alloc}, instance(instance_) {
+    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;
 };
 
@@ -272,6 +270,32 @@
     allocator->pfnFree(allocator->pUserData, instance);
 }
 
+driver::ProcHook::Extension InstanceExtensionToProcHookExtension(
+    InstanceExtension id) {
+    switch (id) {
+        case kKHR_surface:
+            return driver::ProcHook::KHR_surface;
+        case kKHR_android_surface:
+            return driver::ProcHook::KHR_android_surface;
+        case kEXT_debug_report:
+            return driver::ProcHook::EXT_debug_report;
+        default:
+            return driver::ProcHook::EXTENSION_UNKNOWN;
+    }
+}
+
+driver::ProcHook::Extension DeviceExtensionToProcHookExtension(
+    DeviceExtension id) {
+    switch (id) {
+        case kKHR_swapchain:
+            return driver::ProcHook::KHR_swapchain;
+        case kANDROID_native_buffer:
+            return driver::ProcHook::ANDROID_native_buffer;
+        default:
+            return driver::ProcHook::EXTENSION_UNKNOWN;
+    }
+}
+
 }  // anonymous namespace
 
 namespace vulkan {
@@ -297,6 +321,7 @@
 
     // Check that all enabled extensions are supported
     uint32_t num_driver_extensions = 0;
+    bool enable_kEXT_debug_report = false;
     for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
         const char* name = create_info->ppEnabledExtensionNames[i];
         InstanceExtension id = InstanceExtensionFromName(name);
@@ -312,11 +337,27 @@
             }
             // The loader natively supports debug report.
             if (id == kEXT_debug_report) {
+                enable_kEXT_debug_report = true;
                 continue;
             }
         }
     }
 
+    auto& hal_exts = instance.base.hal_extensions;
+    for (size_t i = 0; i < instance.enabled_extensions.size(); i++) {
+        if (instance.enabled_extensions[i]) {
+            auto bit = InstanceExtensionToProcHookExtension(
+                static_cast<InstanceExtension>(i));
+            if (bit != driver::ProcHook::EXTENSION_UNKNOWN)
+                hal_exts.set(bit);
+        }
+    }
+
+    auto& hook_exts = instance.base.hook_extensions;
+    hook_exts = hal_exts;
+    if (enable_kEXT_debug_report)
+        hook_exts.set(driver::ProcHook::EXT_debug_report);
+
     VkInstanceCreateInfo driver_create_info = *create_info;
     driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
     driver_create_info.enabledLayerCount = 0;
@@ -430,111 +471,6 @@
     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) {
@@ -549,69 +485,6 @@
     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,
@@ -646,16 +519,6 @@
     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,
@@ -710,6 +573,26 @@
         }
     }
 
+    // Unlike instance->enabled_extensions, device->enabled_extensions maps to
+    // hook extensions.
+    auto& hook_exts = device->base.hook_extensions;
+    for (size_t i = 0; i < device->enabled_extensions.size(); i++) {
+        if (device->enabled_extensions[i]) {
+            auto bit = DeviceExtensionToProcHookExtension(
+                static_cast<DeviceExtension>(i));
+            if (bit != driver::ProcHook::EXTENSION_UNKNOWN)
+                hook_exts.set(bit);
+        }
+    }
+
+    auto& hal_exts = device->base.hal_extensions;
+    hal_exts = hook_exts;
+    // map VK_KHR_swapchain to VK_ANDROID_native_buffer
+    if (hal_exts[driver::ProcHook::KHR_swapchain]) {
+        hal_exts.reset(driver::ProcHook::KHR_swapchain);
+        hal_exts.set(driver::ProcHook::ANDROID_native_buffer);
+    }
+
     driver_create_info.enabledExtensionCount = num_driver_extensions;
     driver_create_info.ppEnabledExtensionNames = driver_extensions;
     VkDevice drv_device;
@@ -725,9 +608,11 @@
         return VK_ERROR_INITIALIZATION_FAILED;
     }
 
-    device->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
-        instance.drv.dispatch.GetDeviceProcAddr(drv_device,
-                                                "vkGetDeviceProcAddr"));
+    device->base.get_device_proc_addr =
+        reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+            instance.drv.dispatch.GetDeviceProcAddr(drv_device,
+                                                    "vkGetDeviceProcAddr"));
+
     *device_out = drv_device;
     return VK_SUCCESS;
 }
@@ -745,91 +630,6 @@
     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);
 }
@@ -904,14 +704,6 @@
 
 namespace driver {
 
-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,
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 255b6c5..15b773d 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -43,7 +43,6 @@
 // -----------------------------------------------------------------------------
 // dispatch_gen.cpp
 
-PFN_vkVoidFunction GetLoaderBottomProcAddr(const char* name);
 bool LoadDriverDispatchTable(VkInstance instance,
                              PFN_vkGetInstanceProcAddr get_proc_addr,
                              const InstanceExtensionSet& extensions,
@@ -56,20 +55,10 @@
 
 // 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);
@@ -98,18 +87,6 @@
 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
 
 // -----------------------------------------------------------------------------