vulkan: rework {Create,Destroy}Device_Bottom

The reworked driver::CreateDevice will

 - use the providied pAllocator,
 - call HAL's EnumerateDeviceExtensionProperties and filter out extensions
   unknown to HAL, if there is any extension enabled.

We do not expect or enumerate any HAL layer yet as that requires some
works to layers_extensions.cpp.

Change-Id: I3ba4019d18dfed994d7037d95825bf54096f2a5d
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index f3e7dbf..3a6f0a9 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -792,6 +792,8 @@
 
       {{if eq $.Name "vkGetInstanceProcAddr"}}
         reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      {{else if eq $.Name "vkCreateDevice"}}
+        reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
       {{else}}
         reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
       {{end}}
@@ -830,15 +832,10 @@
         reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
       {{end}}
     {{else}}
-        ProcHook::EXTENSION_CORE,
-
-        {{if eq $.Name "vkDestroyDevice"}}
-          reinterpret_cast<PFN_vkVoidFunction>({{$base}}_Bottom),
-        {{else}}
-          reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
-        {{end}}
-        nullptr,
-        nullptr,
+      ProcHook::EXTENSION_CORE,
+      reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
+      nullptr,
+      nullptr,
     {{end}}
   },
 {{end}}
@@ -862,6 +859,8 @@
     {{else if eq $.Name "vkDestroyInstance"}}true
     {{else if eq $.Name "vkDestroyDevice"}}true
 
+    {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
+
     {{/* Enumeration of extensions */}}
     {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 1301912..02e60b7 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <algorithm>
+#include <new>
 #include <malloc.h>
 #include <sys/prctl.h>
 
@@ -44,6 +45,281 @@
 
 namespace {
 
+class CreateInfoWrapper {
+   public:
+    CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                      const VkDeviceCreateInfo& create_info,
+                      const VkAllocationCallbacks& allocator);
+    ~CreateInfoWrapper();
+
+    VkResult validate();
+
+    const std::bitset<ProcHook::EXTENSION_COUNT>& get_hook_extensions() const;
+    const std::bitset<ProcHook::EXTENSION_COUNT>& get_hal_extensions() const;
+
+    explicit operator const VkDeviceCreateInfo*() const;
+
+   private:
+    struct ExtensionFilter {
+        VkExtensionProperties* exts;
+        uint32_t ext_count;
+
+        const char** names;
+        uint32_t name_count;
+    };
+
+    VkResult sanitize_pnext();
+
+    VkResult sanitize_layers();
+    VkResult sanitize_extensions();
+
+    VkResult query_extension_count(uint32_t& count) const;
+    VkResult enumerate_extensions(uint32_t& count,
+                                  VkExtensionProperties* props) const;
+    VkResult init_extension_filter();
+    void filter_extension(const char* name);
+
+    const bool is_instance_;
+    const VkAllocationCallbacks& allocator_;
+
+    union {
+        hwvulkan_device_t* hw_dev_;
+        VkPhysicalDevice physical_dev_;
+    };
+
+    union {
+        VkInstanceCreateInfo instance_info_;
+        VkDeviceCreateInfo dev_info_;
+    };
+
+    ExtensionFilter extension_filter_;
+
+    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
+    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions_;
+};
+
+CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
+                                     const VkDeviceCreateInfo& create_info,
+                                     const VkAllocationCallbacks& allocator)
+    : is_instance_(false),
+      allocator_(allocator),
+      physical_dev_(physical_dev),
+      dev_info_(create_info),
+      extension_filter_() {
+    hook_extensions_.set(ProcHook::EXTENSION_CORE);
+    hal_extensions_.set(ProcHook::EXTENSION_CORE);
+}
+
+CreateInfoWrapper::~CreateInfoWrapper() {
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
+    allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
+}
+
+VkResult CreateInfoWrapper::validate() {
+    VkResult result = sanitize_pnext();
+    if (result == VK_SUCCESS)
+        result = sanitize_layers();
+    if (result == VK_SUCCESS)
+        result = sanitize_extensions();
+
+    return result;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::get_hook_extensions() const {
+    return hook_extensions_;
+}
+
+const std::bitset<ProcHook::EXTENSION_COUNT>&
+CreateInfoWrapper::get_hal_extensions() const {
+    return hal_extensions_;
+}
+
+CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
+    return &dev_info_;
+}
+
+VkResult CreateInfoWrapper::sanitize_pnext() {
+    const struct StructHeader {
+        VkStructureType type;
+        const void* next;
+    } * header;
+
+    if (is_instance_) {
+        header = reinterpret_cast<const StructHeader*>(instance_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        instance_info_.pNext = header;
+    } else {
+        header = reinterpret_cast<const StructHeader*>(dev_info_.pNext);
+
+        // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs
+        while (header &&
+               header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)
+            header = reinterpret_cast<const StructHeader*>(header->next);
+
+        dev_info_.pNext = header;
+    }
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::sanitize_layers() {
+    auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames
+                                       : dev_info_.ppEnabledLayerNames;
+    auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount
+                                       : dev_info_.enabledLayerCount;
+
+    // remove all layers
+    layer_names = nullptr;
+    layer_count = 0;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::sanitize_extensions() {
+    auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames
+                                     : dev_info_.ppEnabledExtensionNames;
+    auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    if (!ext_count)
+        return VK_SUCCESS;
+
+    VkResult result = init_extension_filter();
+    if (result != VK_SUCCESS)
+        return result;
+
+    for (uint32_t i = 0; i < ext_count; i++)
+        filter_extension(ext_names[i]);
+
+    ext_names = extension_filter_.names;
+    ext_count = extension_filter_.name_count;
+
+    return VK_SUCCESS;
+}
+
+VkResult CreateInfoWrapper::query_extension_count(uint32_t& count) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             nullptr);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, nullptr);
+    }
+}
+
+VkResult CreateInfoWrapper::enumerate_extensions(
+    uint32_t& count,
+    VkExtensionProperties* props) const {
+    if (is_instance_) {
+        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
+                                                             props);
+    } else {
+        const auto& driver = GetData(physical_dev_).driver;
+        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
+                                                         &count, props);
+    }
+}
+
+VkResult CreateInfoWrapper::init_extension_filter() {
+    // query extension count
+    uint32_t count;
+    VkResult result = query_extension_count(count);
+    if (result != VK_SUCCESS || count == 0)
+        return result;
+
+    auto& filter = extension_filter_;
+    filter.exts =
+        reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
+            allocator_.pUserData, sizeof(VkExtensionProperties) * count,
+            alignof(VkExtensionProperties),
+            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.exts)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    // enumerate extensions
+    result = enumerate_extensions(count, filter.exts);
+    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
+        return result;
+
+    if (!count)
+        return VK_SUCCESS;
+
+    filter.ext_count = count;
+
+    // allocate name array
+    uint32_t enabled_ext_count = (is_instance_)
+                                     ? instance_info_.enabledExtensionCount
+                                     : dev_info_.enabledExtensionCount;
+    count = std::min(filter.ext_count, enabled_ext_count);
+    filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
+        allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
+        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
+    if (!filter.names)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    return VK_SUCCESS;
+}
+
+void CreateInfoWrapper::filter_extension(const char* name) {
+    auto& filter = extension_filter_;
+
+    ProcHook::Extension ext_bit = GetProcHookExtension(name);
+    if (is_instance_) {
+        switch (ext_bit) {
+            case ProcHook::KHR_android_surface:
+            case ProcHook::KHR_surface:
+                hook_extensions_.set(ext_bit);
+                // return now as these extensions do not require HAL support
+                return;
+            case ProcHook::EXT_debug_report:
+                // both we and HAL can take part in
+                hook_extensions_.set(ext_bit);
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid instance extension %s", name);
+                return;
+        }
+    } else {
+        switch (ext_bit) {
+            case ProcHook::KHR_swapchain:
+                // map VK_KHR_swapchain to VK_ANDROID_native_buffer
+                name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
+                ext_bit = ProcHook::ANDROID_native_buffer;
+                break;
+            case ProcHook::EXTENSION_UNKNOWN:
+                // HAL's extensions
+                break;
+            default:
+                ALOGW("Ignored invalid device extension %s", name);
+                return;
+        }
+    }
+
+    for (uint32_t i = 0; i < filter.ext_count; i++) {
+        const VkExtensionProperties& props = filter.exts[i];
+        // ignore unknown extensions
+        if (strcmp(name, props.extensionName) != 0)
+            continue;
+
+        if (ext_bit == ProcHook::ANDROID_native_buffer)
+            hook_extensions_.set(ProcHook::KHR_swapchain);
+
+        filter.names[filter.name_count++] = name;
+        hal_extensions_.set(ext_bit);
+
+        break;
+    }
+}
+
 hwvulkan_device_t* g_hwdevice = nullptr;
 
 VKAPI_ATTR void* DefaultAllocate(void*,
@@ -94,6 +370,21 @@
     free(ptr);
 }
 
+DeviceData* AllocateDeviceData(const VkAllocationCallbacks& allocator) {
+    void* data_mem = allocator.pfnAllocation(
+        allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
+        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
+    if (!data_mem)
+        return nullptr;
+
+    return new (data_mem) DeviceData(allocator);
+}
+
+void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
+    data->~DeviceData();
+    allocator.pfnFree(allocator.pUserData, data);
+}
+
 }  // anonymous namespace
 
 bool Debuggable() {
@@ -205,6 +496,67 @@
                : hook->disabled_proc;
 }
 
+VkResult CreateDevice(VkPhysicalDevice physicalDevice,
+                      const VkDeviceCreateInfo* pCreateInfo,
+                      const VkAllocationCallbacks* pAllocator,
+                      VkDevice* pDevice) {
+    const InstanceData& instance_data = GetData(physicalDevice);
+    const VkAllocationCallbacks& data_allocator =
+        (pAllocator) ? *pAllocator : instance_data.allocator;
+
+    CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
+    VkResult result = wrapper.validate();
+    if (result != VK_SUCCESS)
+        return result;
+
+    DeviceData* data = AllocateDeviceData(data_allocator);
+    if (!data)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    data->hook_extensions |= wrapper.get_hook_extensions();
+    data->hal_extensions |= wrapper.get_hal_extensions();
+
+    // call into the driver
+    VkDevice dev;
+    result = instance_data.driver.CreateDevice(
+        physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
+        pAllocator, &dev);
+    if (result != VK_SUCCESS) {
+        FreeDeviceData(data, data_allocator);
+        return result;
+    }
+
+    // initialize DeviceDriverTable
+    if (!SetData(dev, *data) ||
+        !InitDriverTable(dev, instance_data.get_device_proc_addr)) {
+        data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
+            instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
+        if (data->driver.DestroyDevice)
+            data->driver.DestroyDevice(dev, pAllocator);
+
+        FreeDeviceData(data, data_allocator);
+
+        return VK_ERROR_INCOMPATIBLE_DRIVER;
+    }
+
+    *pDevice = dev;
+
+    return VK_SUCCESS;
+}
+
+void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
+    DeviceData& data = GetData(device);
+    data.driver.DestroyDevice(device, pAllocator);
+
+    VkAllocationCallbacks local_allocator;
+    if (!pAllocator) {
+        local_allocator = data.allocator;
+        pAllocator = &local_allocator;
+    }
+
+    FreeDeviceData(&data, *pAllocator);
+}
+
 void GetDeviceQueue(VkDevice device,
                     uint32_t queueFamilyIndex,
                     uint32_t queueIndex,
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 7302037..b3678dc 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -109,6 +109,9 @@
 VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName);
 VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
 
+VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
+VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
+
 VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
 VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
 // clang-format on
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index dd203c7..81299fc 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -164,7 +164,7 @@
         "vkCreateDevice",
         ProcHook::INSTANCE,
         ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(CreateDevice_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
         nullptr,
         nullptr,
     },
@@ -204,7 +204,7 @@
         "vkDestroyDevice",
         ProcHook::DEVICE,
         ProcHook::EXTENSION_CORE,
-        reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice_Bottom),
+        reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
         nullptr,
         nullptr,
     },
@@ -397,6 +397,7 @@
     INIT_PROC(instance, EnumeratePhysicalDevices);
     INIT_PROC(instance, GetInstanceProcAddr);
     INIT_PROC(instance, CreateDevice);
+    INIT_PROC(instance, EnumerateDeviceLayerProperties);
     INIT_PROC(instance, EnumerateDeviceExtensionProperties);
     INIT_PROC_EXT(EXT_debug_report, instance, CreateDebugReportCallbackEXT);
     INIT_PROC_EXT(EXT_debug_report, instance, DestroyDebugReportCallbackEXT);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 4226a63..1eb7d79 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -58,6 +58,7 @@
     PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
     PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
     PFN_vkCreateDevice CreateDevice;
+    PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;
     PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index 1212f96..0313f7e 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -163,17 +163,6 @@
     InstanceExtensionSet enabled_extensions;
 };
 
-struct Device {
-    Device(Instance* instance_) : base(*instance_->alloc), instance(instance_) {
-        enabled_extensions.reset();
-    }
-
-    driver::DeviceData base;
-
-    Instance* instance;
-    DeviceExtensionSet enabled_extensions;
-};
-
 template <typename THandle>
 struct HandleTraits {};
 template <>
@@ -184,18 +173,6 @@
 struct HandleTraits<VkPhysicalDevice> {
     typedef Instance LoaderObjectType;
 };
-template <>
-struct HandleTraits<VkDevice> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkQueue> {
-    typedef Device LoaderObjectType;
-};
-template <>
-struct HandleTraits<VkCommandBuffer> {
-    typedef Device LoaderObjectType;
-};
 
 template <typename THandle>
 typename HandleTraits<THandle>::LoaderObjectType& GetDispatchParent(
@@ -218,16 +195,6 @@
 
 // -----------------------------------------------------------------------------
 
-void DestroyDevice(Device* device, VkDevice vkdevice) {
-    const auto& instance = *device->instance;
-
-    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);
-}
-
 /*
  * This function will return the pNext pointer of any
  * CreateInfo extensions that are not loader extensions.
@@ -522,105 +489,6 @@
     return *properties_count < num_extensions ? VK_INCOMPLETE : VK_SUCCESS;
 }
 
-VKAPI_ATTR
-VkResult CreateDevice_Bottom(VkPhysicalDevice gpu,
-                             const VkDeviceCreateInfo* create_info,
-                             const VkAllocationCallbacks* allocator,
-                             VkDevice* device_out) {
-    Instance& instance = GetDispatchParent(gpu);
-
-    // FIXME(jessehall): We don't have good conventions or infrastructure yet to
-    // do better than just using the instance allocator and scope for
-    // everything. See b/26732122.
-    if (true /*!allocator*/)
-        allocator = instance.alloc;
-
-    void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Device),
-                                         alignof(Device),
-                                         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
-    if (!mem)
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    Device* device = new (mem) Device(&instance);
-
-    size_t gpu_idx = 0;
-    while (instance.physical_devices[gpu_idx] != gpu)
-        gpu_idx++;
-
-    VkDeviceCreateInfo driver_create_info = *create_info;
-    driver_create_info.pNext = StripCreateExtensions(create_info->pNext);
-    driver_create_info.enabledLayerCount = 0;
-    driver_create_info.ppEnabledLayerNames = nullptr;
-
-    uint32_t num_driver_extensions = 0;
-    const char** driver_extensions = static_cast<const char**>(
-        alloca(create_info->enabledExtensionCount * sizeof(const char*)));
-    for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++) {
-        const char* name = create_info->ppEnabledExtensionNames[i];
-        DeviceExtension id = DeviceExtensionFromName(name);
-        if (id != kDeviceExtensionCount) {
-            if (instance.physical_device_driver_extensions[gpu_idx][id]) {
-                driver_extensions[num_driver_extensions++] = name;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-            // Add the VK_ANDROID_native_buffer extension to the list iff
-            // the VK_KHR_swapchain extension was requested
-            if (id == kKHR_swapchain &&
-                instance.physical_device_driver_extensions
-                    [gpu_idx][kANDROID_native_buffer]) {
-                driver_extensions[num_driver_extensions++] =
-                    VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
-                device->enabled_extensions.set(id);
-                continue;
-            }
-        }
-    }
-
-    // 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;
-    VkResult result = instance.base.driver.CreateDevice(
-        gpu, &driver_create_info, allocator, &drv_device);
-    if (result != VK_SUCCESS) {
-        DestroyDevice(device, VK_NULL_HANDLE);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    if (!driver::SetData(drv_device, device->base)) {
-        DestroyDevice(device, drv_device);
-        return VK_ERROR_INITIALIZATION_FAILED;
-    }
-
-    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;
-}
-
 void DestroyInstance_Bottom(VkInstance vkinstance,
                             const VkAllocationCallbacks* allocator) {
     Instance& instance = GetDispatchParent(vkinstance);
@@ -634,10 +502,6 @@
     DestroyInstance(&instance, allocator, vkinstance);
 }
 
-void DestroyDevice_Bottom(VkDevice vkdevice, const VkAllocationCallbacks*) {
-    DestroyDevice(&GetDispatchParent(vkdevice), vkdevice);
-}
-
 // -----------------------------------------------------------------------------
 
 const VkAllocationCallbacks* GetAllocator(VkInstance vkinstance) {
@@ -645,7 +509,7 @@
 }
 
 const VkAllocationCallbacks* GetAllocator(VkDevice vkdevice) {
-    return GetDispatchParent(vkdevice).instance->alloc;
+    return &driver::GetData(vkdevice).allocator;
 }
 
 VkInstance GetDriverInstance(VkInstance instance) {
diff --git a/vulkan/libvulkan/loader.h b/vulkan/libvulkan/loader.h
index 823c446..8c8c8fc 100644
--- a/vulkan/libvulkan/loader.h
+++ b/vulkan/libvulkan/loader.h
@@ -50,9 +50,7 @@
 VKAPI_ATTR VkResult CreateInstance_Bottom(const VkInstanceCreateInfo* create_info, const VkAllocationCallbacks* allocator, VkInstance* vkinstance);
 VKAPI_ATTR VkResult EnumeratePhysicalDevices_Bottom(VkInstance vkinstance, uint32_t* pdev_count, VkPhysicalDevice* pdevs);
 VKAPI_ATTR VkResult EnumerateDeviceExtensionProperties_Bottom(VkPhysicalDevice pdev, const char* layer_name, uint32_t* properties_count, VkExtensionProperties* 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 void DestroyDevice_Bottom(VkDevice device, const VkAllocationCallbacks* pAllocator);
 // clang-format on
 
 const VkAllocationCallbacks* GetAllocator(VkInstance instance);