Add layer loading to android vulkan loader.

Change-Id: I500d248f03a14db82ce725e600aef82c115b9b35
(cherry picked from commit ad17ac2e5bec7a65e3170043eb958e5a97107bd4)
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
index e178ee2..bcb1e8b 100644
--- a/vulkan/libvulkan/Android.mk
+++ b/vulkan/libvulkan/Android.mk
@@ -36,7 +36,7 @@
 	swapchain.cpp
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_SHARED_LIBRARIES := libhardware liblog libsync
+LOCAL_SHARED_LIBRARIES := libhardware liblog libsync libcutils
 
 LOCAL_MODULE := libvulkan
 include $(BUILD_SHARED_LIBRARY)
diff --git a/vulkan/libvulkan/get_proc_addr.cpp b/vulkan/libvulkan/get_proc_addr.cpp
index 6d79972..ceb76b9 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp
+++ b/vulkan/libvulkan/get_proc_addr.cpp
@@ -453,11 +453,22 @@
         const_cast<unsigned char*>(base) + entry->offset);
 }
 
+// TODO: remove need for instance_next
 bool LoadInstanceVtbl(VkInstance instance,
+                      VkInstance instance_next,
                       PFN_vkGetInstanceProcAddr get_proc_addr,
                       InstanceVtbl& vtbl) {
     bool success = true;
     // clang-format off
+    vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance_next, "vkGetInstanceProcAddr"));
+    if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
+        ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
+        success = false;
+    }
+    vtbl.CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(get_proc_addr(instance, "vkCreateInstance"));
+    if (UNLIKELY(!vtbl.CreateInstance)) {
+        // This is allowed to fail as the driver doesn't have to return vkCreateInstance when given an instance
+    }
     vtbl.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(get_proc_addr(instance, "vkDestroyInstance"));
     if (UNLIKELY(!vtbl.DestroyInstance)) {
         ALOGE("missing instance proc: %s", "vkDestroyInstance");
@@ -468,11 +479,6 @@
         ALOGE("missing instance proc: %s", "vkEnumeratePhysicalDevices");
         success = false;
     }
-    vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance, "vkGetInstanceProcAddr"));
-    if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
-        ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
-        success = false;
-    }
     vtbl.GetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(get_proc_addr(instance, "vkGetPhysicalDeviceProperties"));
     if (UNLIKELY(!vtbl.GetPhysicalDeviceProperties)) {
         ALOGE("missing instance proc: %s", "vkGetPhysicalDeviceProperties");
@@ -538,11 +544,12 @@
 }
 
 bool LoadDeviceVtbl(VkDevice device,
+                    VkDevice device_next,
                     PFN_vkGetDeviceProcAddr get_proc_addr,
                     DeviceVtbl& vtbl) {
     bool success = true;
     // clang-format off
-    vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device, "vkGetDeviceProcAddr"));
+    vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device_next, "vkGetDeviceProcAddr"));
     if (UNLIKELY(!vtbl.GetDeviceProcAddr)) {
         ALOGE("missing device proc: %s", "vkGetDeviceProcAddr");
         success = false;
diff --git a/vulkan/libvulkan/get_proc_addr.cpp.tmpl b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
index 36a45d9..2e63893 100644
--- a/vulkan/libvulkan/get_proc_addr.cpp.tmpl
+++ b/vulkan/libvulkan/get_proc_addr.cpp.tmpl
@@ -201,12 +201,23 @@
 }

 bool LoadInstanceVtbl(VkInstance instance,
+                      VkInstance instance_next,
                       PFN_vkGetInstanceProcAddr get_proc_addr,
                       InstanceVtbl& vtbl) {«
     bool success = true;
     // clang-format off
+    vtbl.GetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(get_proc_addr(instance_next, "vkGetInstanceProcAddr"));
+    if (UNLIKELY(!vtbl.GetInstanceProcAddr)) {
+        ALOGE("missing instance proc: %s", "vkGetInstanceProcAddr");
+        success = false;
+    }
+    vtbl.CreateInstance = reinterpret_cast<PFN_vkCreateInstance>(get_proc_addr(instance, "vkCreateInstance"));
+    if (UNLIKELY(!vtbl.CreateInstance)) {
+        // This is allowed to fail as the driver doesn't have to return vkCreateInstance when given an instance
+    }
     {{range $f := AllCommands $}}
       {{if eq (Macro "Vtbl" $f) "Instance"}}
+        {{if not (eq (Macro "FunctionName" $f) "vkGetInstanceProcAddr")}}
     vtbl.{{TrimPrefix "vk" (Macro "FunctionName" $f)}} = §
         reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
             get_proc_addr(instance, "{{Macro "FunctionName" $f}}"));
@@ -214,6 +225,7 @@
         ALOGE("missing instance proc: %s", "{{Macro "FunctionName" $f}}");
         success = false;
     }
+        {{end}}
       {{end}}
     {{end}}
     // clang-format on
@@ -221,12 +233,19 @@
 »}

 bool LoadDeviceVtbl(VkDevice device,
+                    VkDevice device_next,
                     PFN_vkGetDeviceProcAddr get_proc_addr,
                     DeviceVtbl& vtbl) {«
     bool success = true;
     // clang-format off
+    vtbl.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(get_proc_addr(device_next, "vkGetDeviceProcAddr"));
+    if (UNLIKELY(!vtbl.GetDeviceProcAddr)) {
+        ALOGE("missing device proc: %s", "vkGetDeviceProcAddr");
+        success = false;
+    }
     {{range $f := AllCommands $}}
       {{if eq (Macro "Vtbl" $f) "Device"}}
+        {{if not (eq (Macro "FunctionName" $f) "vkGetDeviceProcAddr")}}
     vtbl.{{TrimPrefix "vk" (Macro "FunctionName" $f)}} = §
         reinterpret_cast<{{Macro "FunctionPtrName" $f}}>(§
             get_proc_addr(device, "{{Macro "FunctionName" $f}}"));
@@ -234,6 +253,7 @@
         ALOGE("missing device proc: %s", "{{Macro "FunctionName" $f}}");
         success = false;
     }
+        {{end}}
       {{end}}
     {{end}}
     vtbl.ImportNativeFenceANDROID = reinterpret_cast<PFN_vkImportNativeFenceANDROID>(get_proc_addr(device, "vkImportNativeFenceANDROID"));
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 3ba47b3..6b223aa 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -17,6 +17,8 @@
 // module header
 #include "loader.h"
 // standard C headers
+#include <dirent.h>
+#include <dlfcn.h>
 #include <inttypes.h>
 #include <malloc.h>
 #include <pthread.h>
@@ -24,7 +26,12 @@
 // standard C++ headers
 #include <algorithm>
 #include <mutex>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
 // platform/library headers
+#include <cutils/properties.h>
 #include <hardware/hwvulkan.h>
 #include <log/log.h>
 
@@ -32,9 +39,86 @@
 
 static const uint32_t kMaxPhysicalDevices = 4;
 
+namespace {
+
+// These definitions are taken from the LunarG Vulkan Loader. They are used to
+// enforce compatability between the Loader and Layers.
+typedef void* (*PFN_vkGetProcAddr)(void* obj, const char* pName);
+
+typedef struct VkLayerLinkedListElem_ {
+    PFN_vkGetProcAddr get_proc_addr;
+    void* next_element;
+    void* base_object;
+} VkLayerLinkedListElem;
+
+// Define Handle typedef to be void* as returned from dlopen.
+typedef void* SharedLibraryHandle;
+
+// Custom versions of std classes that use the vulkan alloc callback.
+template <class T>
+class CallbackAllocator {
+   public:
+    typedef T value_type;
+
+    CallbackAllocator(const VkAllocCallbacks* alloc_input)
+        : alloc(alloc_input) {}
+
+    template <class T2>
+    CallbackAllocator(const CallbackAllocator<T2>& other)
+        : alloc(other.alloc) {}
+
+    T* allocate(std::size_t n) {
+        void* mem = alloc->pfnAlloc(alloc->pUserData, n * sizeof(T), alignof(T),
+                                    VK_SYSTEM_ALLOC_TYPE_INTERNAL);
+        return static_cast<T*>(mem);
+    }
+
+    void deallocate(T* array, std::size_t /*n*/) {
+        alloc->pfnFree(alloc->pUserData, array);
+    }
+
+    const VkAllocCallbacks* alloc;
+};
+// These are needed in order to move Strings
+template <class T>
+bool operator==(const CallbackAllocator<T>& alloc1,
+                const CallbackAllocator<T>& alloc2) {
+    return alloc1.alloc == alloc2.alloc;
+}
+template <class T>
+bool operator!=(const CallbackAllocator<T>& alloc1,
+                const CallbackAllocator<T>& alloc2) {
+    return !(alloc1 == alloc2);
+}
+
+template <class Key,
+          class T,
+          class Hash = std::hash<Key>,
+          class Pred = std::equal_to<Key> >
+using UnorderedMap =
+    std::unordered_map<Key,
+                       T,
+                       Hash,
+                       Pred,
+                       CallbackAllocator<std::pair<const Key, T> > >;
+
+template <class T>
+using Vector = std::vector<T, CallbackAllocator<T> >;
+
+typedef std::basic_string<char,
+                          std::char_traits<char>,
+                          CallbackAllocator<char> > String;
+
+}  // namespace
+
+// -----------------------------------------------------------------------------
+
 struct VkInstance_T {
     VkInstance_T(const VkAllocCallbacks* alloc_callbacks)
-        : vtbl(&vtbl_storage), alloc(alloc_callbacks), num_physical_devices(0) {
+        : vtbl(&vtbl_storage),
+          alloc(alloc_callbacks),
+          num_physical_devices(0),
+          layer_handles(CallbackAllocator<SharedLibraryHandle>(alloc)) {
         memset(&vtbl_storage, 0, sizeof(vtbl_storage));
         memset(physical_devices, 0, sizeof(physical_devices));
         memset(&drv.vtbl, 0, sizeof(drv.vtbl));
@@ -49,6 +133,8 @@
     uint32_t num_physical_devices;
     VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
 
+    Vector<SharedLibraryHandle> layer_handles;
+
     struct Driver {
         // Pointers to driver entry points. Used explicitly by the loader; not
         // set as the dispatch table for any objects.
@@ -77,6 +163,7 @@
     }
     DeviceVtbl vtbl_storage;
     const VkAllocCallbacks* alloc;
+    PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
 };
 
 // -----------------------------------------------------------------------------
@@ -141,6 +228,93 @@
     alloc->pfnFree(alloc->pUserData, device);
 }
 
+void FindLayersInDirectory(
+    Instance& instance,
+    UnorderedMap<String, SharedLibraryHandle>& layer_name_to_handle_map,
+    const String& dir_name) {
+    DIR* directory;
+    struct dirent* entry;
+    if ((directory = opendir(dir_name.c_str()))) {
+        Vector<VkLayerProperties> properties(
+            CallbackAllocator<VkLayerProperties>(instance.alloc));
+        while ((entry = readdir(directory))) {
+            size_t length = strlen(entry->d_name);
+            if (strncmp(entry->d_name, "libVKLayer", 10) != 0 ||
+                strncmp(entry->d_name + length - 3, ".so", 3) != 0)
+                continue;
+            // Open so
+            SharedLibraryHandle layer_handle = dlopen(
+                (dir_name + entry->d_name).c_str(), RTLD_NOW | RTLD_LOCAL);
+            if (!layer_handle) {
+                ALOGE("%s failed to load with error %s; Skipping",
+                      entry->d_name, dlerror());
+                continue;
+            }
+
+            // Get Layers in so
+            PFN_vkGetGlobalLayerProperties get_layer_properties =
+                reinterpret_cast<PFN_vkGetGlobalLayerProperties>(
+                    dlsym(layer_handle, "vkGetGlobalLayerProperties"));
+            if (!get_layer_properties) {
+                ALOGE(
+                    "%s failed to find vkGetGlobalLayerProperties with "
+                    "error %s; Skipping",
+                    entry->d_name, dlerror());
+                dlclose(layer_handle);
+                continue;
+            }
+            uint32_t count;
+            get_layer_properties(&count, nullptr);
+
+            properties.resize(count);
+            get_layer_properties(&count, &properties[0]);
+
+            // Add Layers to potential list
+            // TODO: Add support for multiple layers in 1 so.
+            ALOGW_IF(count > 1,
+                     "More than 1 layer per library file is not currently "
+                     "supported.");
+            for (uint32_t i = 0; i < count; ++i) {
+                layer_name_to_handle_map.insert(std::make_pair(
+                    String(properties[i].layerName,
+                           CallbackAllocator<char>(instance.alloc)),
+                    layer_handle));
+                ALOGV("Found layer %s", properties[i].layerName);
+            }
+        }
+        closedir(directory);
+    } else {
+        ALOGE("Failed to Open Directory %s: %s (%d)", dir_name.c_str(),
+              strerror(errno), errno);
+    }
+}
+
+void LoadLayer(Instance* instance,
+               const String& name,
+               SharedLibraryHandle& layer_handle) {
+    ALOGV("Loading layer %s", name.c_str());
+    instance->layer_handles.push_back(layer_handle);
+}
+
+VkResult CreateDeviceNoop(VkPhysicalDevice,
+                          const VkDeviceCreateInfo*,
+                          VkDevice*) {
+    return VK_SUCCESS;
+}
+
+PFN_vkVoidFunction GetLayerDeviceProcAddr(VkDevice device, const char* name) {
+    if (strcmp(name, "vkGetDeviceProcAddr") == 0) {
+        return reinterpret_cast<PFN_vkVoidFunction>(GetLayerDeviceProcAddr);
+    }
+    if (strcmp(name, "vkCreateDevice") == 0) {
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateDeviceNoop);
+    }
+    if (!device)
+        return GetGlobalDeviceProcAddr(name);
+    Device* loader_device = reinterpret_cast<Device*>(GetVtbl(device)->device);
+    return loader_device->GetDeviceProcAddr(device, name);
+}
+
 // -----------------------------------------------------------------------------
 // "Bottom" functions. These are called at the end of the instance dispatch
 // chain.
@@ -152,6 +326,9 @@
         instance->drv.vtbl.DestroyInstance) {
         instance->drv.vtbl.DestroyInstance(instance->drv.vtbl.instance);
     }
+    for (auto layer_handle : instance->layer_handles) {
+        dlclose(layer_handle);
+    }
     const VkAllocCallbacks* alloc = instance->alloc;
     instance->~VkInstance_T();
     alloc->pfnFree(alloc->pUserData, instance);
@@ -170,9 +347,9 @@
         return result;
     }
 
-    if (!LoadInstanceVtbl(instance->drv.vtbl.instance,
-                          g_hwdevice->GetInstanceProcAddr,
-                          instance->drv.vtbl)) {
+    if (!LoadInstanceVtbl(
+            instance->drv.vtbl.instance, instance->drv.vtbl.instance,
+            g_hwdevice->GetInstanceProcAddr, instance->drv.vtbl)) {
         DestroyInstanceBottom(instance);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
@@ -319,6 +496,7 @@
     if (!mem)
         return VK_ERROR_OUT_OF_HOST_MEMORY;
     Device* device = new (mem) Device(instance.alloc);
+    device->GetDeviceProcAddr = instance.drv.GetDeviceProcAddr;
 
     VkDevice drv_device;
     result = instance.drv.vtbl.CreateDevice(pdev, create_info, &drv_device);
@@ -327,19 +505,14 @@
         return result;
     }
 
-    if (!LoadDeviceVtbl(drv_device, instance.drv.GetDeviceProcAddr,
-                        device->vtbl_storage)) {
-        if (device->vtbl_storage.DestroyDevice)
-            device->vtbl_storage.DestroyDevice(drv_device);
-        DestroyDevice(device);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
     hwvulkan_dispatch_t* dispatch =
         reinterpret_cast<hwvulkan_dispatch_t*>(drv_device);
     if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
         ALOGE("invalid VkDevice dispatch magic: 0x%" PRIxPTR, dispatch->magic);
-        device->vtbl_storage.DestroyDevice(drv_device);
+        PFN_vkDestroyDevice destroy_device =
+            reinterpret_cast<PFN_vkDestroyDevice>(
+                instance.drv.GetDeviceProcAddr(drv_device, "vkDestroyDevice"));
+        destroy_device(drv_device);
         DestroyDevice(device);
         return VK_ERROR_INITIALIZATION_FAILED;
     }
@@ -354,7 +527,45 @@
     device->vtbl_storage.AcquireNextImageKHR = AcquireNextImageKHR;
     device->vtbl_storage.QueuePresentKHR = QueuePresentKHR;
 
-    // TODO: insert device layer entry points into device->vtbl_storage here?
+    void* base_object = static_cast<void*>(drv_device);
+    void* next_object = base_object;
+    VkLayerLinkedListElem* next_element;
+    PFN_vkGetDeviceProcAddr next_get_proc_addr = GetLayerDeviceProcAddr;
+    Vector<VkLayerLinkedListElem> elem_list(
+        instance.layer_handles.size(),
+        CallbackAllocator<VkLayerLinkedListElem>(instance.alloc));
+
+    for (size_t i = elem_list.size(); i > 0; i--) {
+        size_t idx = i - 1;
+        next_element = &elem_list[idx];
+        next_element->get_proc_addr =
+            reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
+        next_element->base_object = base_object;
+        next_element->next_element = next_object;
+        next_object = static_cast<void*>(next_element);
+
+        next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+            dlsym(instance.layer_handles[idx], "vkGetDeviceProcAddr"));
+        if (!next_get_proc_addr) {
+            ALOGE("Cannot find vkGetDeviceProcAddr, error is %s", dlerror());
+            next_object = next_element->next_element;
+            next_get_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
+                next_element->get_proc_addr);
+        }
+    }
+
+    if (!LoadDeviceVtbl(static_cast<VkDevice>(base_object),
+                        static_cast<VkDevice>(next_object), next_get_proc_addr,
+                        device->vtbl_storage)) {
+        DestroyDevice(device);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
+    PFN_vkCreateDevice layer_createDevice =
+        reinterpret_cast<PFN_vkCreateDevice>(
+            device->vtbl_storage.GetDeviceProcAddr(drv_device,
+                                                   "vkCreateDevice"));
+    layer_createDevice(pdev, create_info, &drv_device);
 
     *out_device = drv_device;
     return VK_SUCCESS;
@@ -418,9 +629,20 @@
     // clang-format on
 };
 
+VkResult Noop(...) {
+    return VK_SUCCESS;
+}
+
 PFN_vkVoidFunction GetInstanceProcAddrBottom(VkInstance, const char* name) {
-    // The bottom GetInstanceProcAddr is only called by the innermost layer,
-    // when there is one, when it initializes its own dispatch table.
+    // TODO: Possibly move this into the instance table
+    // TODO: Possibly register the callbacks in the loader
+    if (strcmp(name, "vkDbgCreateMsgCallback") == 0 ||
+        strcmp(name, "vkDbgDestroyMsgCallback") == 0) {
+        return reinterpret_cast<PFN_vkVoidFunction>(Noop);
+    }
+    if (strcmp(name, "vkCreateInstance") == 0) {
+        return reinterpret_cast<PFN_vkVoidFunction>(CreateInstanceBottom);
+    }
     return GetSpecificInstanceProcAddr(&kBottomInstanceFunctions, name);
 }
 
@@ -483,12 +705,95 @@
     instance->vtbl_storage = kBottomInstanceFunctions;
     instance->vtbl_storage.instance = instance;
 
-    // TODO: Insert enabled layers into instance->dispatch_vtbl here.
+    // Scan layers
+    // TODO: Add more directories to scan
+    UnorderedMap<String, SharedLibraryHandle> layers(
+        CallbackAllocator<std::pair<String, SharedLibraryHandle> >(
+            instance->alloc));
+    CallbackAllocator<char> string_allocator(instance->alloc);
+    String dir_name("/data/local/tmp/vulkan/", string_allocator);
+    FindLayersInDirectory(*instance, layers, dir_name);
 
-    // TODO: We'll want to call CreateInstance through the dispatch table
-    // instead of calling the loader's terminator
+    // TODO: Add auto enabling of the layer extension
+
+    {
+        char layer_prop[PROPERTY_VALUE_MAX];
+        property_get("vulkan.layers", layer_prop, "");
+        // TODO: Find a way to enable a large number but not all of the layers
+        size_t length = strlen(layer_prop);
+        if (length == 1 && layer_prop[0] == '+') {
+            for (auto& layer : layers) {
+                LoadLayer(instance, layer.first, layer.second);
+            }
+        } else {
+            String layer_name(string_allocator);
+            String layer_prop_str(layer_prop, string_allocator);
+            size_t end, start = 0;
+            while ((end = layer_prop_str.find(':', start)) !=
+                   std::string::npos) {
+                layer_name = layer_prop_str.substr(start, end - start);
+                auto element = layers.find(layer_name);
+                if (element != layers.end()) {
+                    LoadLayer(instance, layer_name, element->second);
+                    layers.erase(element);
+                }
+                start = end + 1;
+            }
+        }
+    }
+
+    for (uint32_t i = 0; i < create_info->layerCount; ++i) {
+        String layer_name(create_info->ppEnabledLayerNames[i],
+                          string_allocator);
+        auto element = layers.find(layer_name);
+        if (element != layers.end()) {
+            LoadLayer(instance, layer_name, element->second);
+            layers.erase(element);
+        }
+    }
+
+    for (auto& layer : layers) {
+        dlclose(layer.second);
+    }
+
+    void* base_object = static_cast<void*>(instance);
+    void* next_object = base_object;
+    VkLayerLinkedListElem* next_element;
+    PFN_vkGetInstanceProcAddr next_get_proc_addr =
+        kBottomInstanceFunctions.GetInstanceProcAddr;
+    Vector<VkLayerLinkedListElem> elem_list(
+        instance->layer_handles.size(),
+        CallbackAllocator<VkLayerLinkedListElem>(instance->alloc));
+
+    for (size_t i = elem_list.size(); i > 0; i--) {
+        size_t idx = i - 1;
+        next_element = &elem_list[idx];
+        next_element->get_proc_addr =
+            reinterpret_cast<PFN_vkGetProcAddr>(next_get_proc_addr);
+        next_element->base_object = base_object;
+        next_element->next_element = next_object;
+        next_object = static_cast<void*>(next_element);
+
+        next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+            dlsym(instance->layer_handles[idx], "vkGetInstanceProcAddr"));
+        if (!next_get_proc_addr) {
+            ALOGE("Cannot find vkGetInstanceProcAddr for, error is %s",
+                  dlerror());
+            next_object = next_element->next_element;
+            next_get_proc_addr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(
+                next_element->get_proc_addr);
+        }
+    }
+
+    if (!LoadInstanceVtbl(static_cast<VkInstance>(base_object),
+                          static_cast<VkInstance>(next_object),
+                          next_get_proc_addr, instance->vtbl_storage)) {
+        DestroyInstanceBottom(instance);
+        return VK_ERROR_INITIALIZATION_FAILED;
+    }
+
     *out_instance = instance;
-    result = CreateInstanceBottom(create_info, out_instance);
+    result = instance->vtbl_storage.CreateInstance(create_info, out_instance);
     if (result <= 0) {
         // For every layer, including the loader top and bottom layers:
         // - If a call to the next CreateInstance fails, the layer must clean
@@ -510,6 +815,14 @@
 PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
     if (!instance)
         return GetGlobalInstanceProcAddr(name);
+    // TODO: Possibly move this into the instance table
+    if (strcmp(name, "vkDbgCreateMsgCallback") == 0 ||
+        strcmp(name, "vkDbgDestroyMsgCallback") == 0) {
+        if (!instance->vtbl)
+            return NULL;
+        PFN_vkGetInstanceProcAddr gpa = instance->vtbl->GetInstanceProcAddr;
+        return reinterpret_cast<PFN_vkVoidFunction>(gpa(instance, name));
+    }
     // For special-case functions we always return the loader entry
     if (strcmp(name, "vkGetInstanceProcAddr") == 0 ||
         strcmp(name, "vkGetDeviceProcAddr") == 0) {
@@ -521,6 +834,9 @@
 PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
     if (!device)
         return GetGlobalDeviceProcAddr(name);
+    if (strcmp(name, "vkGetDeviceProcAddr") == 0) {
+        return reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr);
+    }
     // For special-case functions we always return the loader entry
     if (strcmp(name, "vkGetDeviceQueue") == 0 ||
         strcmp(name, "vkCreateCommandBuffer") == 0 ||
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index d0e476c..5933eb2 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -253,9 +253,11 @@
                                              const char* name);
 
 bool LoadInstanceVtbl(VkInstance instance,
+                      VkInstance next_instance,
                       PFN_vkGetInstanceProcAddr get_proc_addr,
                       InstanceVtbl& vtbl);
 bool LoadDeviceVtbl(VkDevice device,
+                    VkDevice next_device,
                     PFN_vkGetDeviceProcAddr get_proc_addr,
                     DeviceVtbl& vtbl);
 
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 10fb5c9..8f65156 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -120,13 +120,13 @@
 __attribute__((visibility("default"))) hwvulkan_module_t HAL_MODULE_INFO_SYM = {
     .common =
         {
-         .tag = HARDWARE_MODULE_TAG,
-         .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
-         .hal_api_version = HARDWARE_HAL_API_VERSION,
-         .id = HWVULKAN_HARDWARE_MODULE_ID,
-         .name = "Null Vulkan Driver",
-         .author = "The Android Open Source Project",
-         .methods = &nulldrv_module_methods,
+            .tag = HARDWARE_MODULE_TAG,
+            .module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
+            .hal_api_version = HARDWARE_HAL_API_VERSION,
+            .id = HWVULKAN_HARDWARE_MODULE_ID,
+            .name = "Null Vulkan Driver",
+            .author = "The Android Open Source Project",
+            .methods = &nulldrv_module_methods,
         },
 };
 #pragma clang diagnostic pop
@@ -165,10 +165,10 @@
 hwvulkan_device_t nulldrv_device = {
     .common =
         {
-         .tag = HARDWARE_DEVICE_TAG,
-         .version = HWVULKAN_DEVICE_API_VERSION_0_1,
-         .module = &HAL_MODULE_INFO_SYM.common,
-         .close = CloseDevice,
+            .tag = HARDWARE_DEVICE_TAG,
+            .version = HWVULKAN_DEVICE_API_VERSION_0_1,
+            .module = &HAL_MODULE_INFO_SYM.common,
+            .close = CloseDevice,
         },
     .GetGlobalExtensionProperties = GetGlobalExtensionProperties,
     .CreateInstance = CreateInstance,