driver.cpp revision 950d6e1102077d6a3905eb77268800002e792fb0
1/*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#include <algorithm>
20#include <array>
21#include <new>
22#include <malloc.h>
23#include <sys/prctl.h>
24
25#include "driver.h"
26#include "stubhal.h"
27
28// #define ENABLE_ALLOC_CALLSTACKS 1
29#if ENABLE_ALLOC_CALLSTACKS
30#include <utils/CallStack.h>
31#define ALOGD_CALLSTACK(...)                             \
32    do {                                                 \
33        ALOGD(__VA_ARGS__);                              \
34        android::CallStack callstack;                    \
35        callstack.update();                              \
36        callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, "  "); \
37    } while (false)
38#else
39#define ALOGD_CALLSTACK(...) \
40    do {                     \
41    } while (false)
42#endif
43
44namespace vulkan {
45namespace driver {
46
47namespace {
48
49class CreateInfoWrapper {
50   public:
51    CreateInfoWrapper(const hwvulkan_device_t* hw_dev,
52                      const VkInstanceCreateInfo& create_info,
53                      const VkAllocationCallbacks& allocator);
54    CreateInfoWrapper(VkPhysicalDevice physical_dev,
55                      const VkDeviceCreateInfo& create_info,
56                      const VkAllocationCallbacks& allocator);
57    ~CreateInfoWrapper();
58
59    VkResult Validate();
60
61    const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
62    const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
63
64    explicit operator const VkInstanceCreateInfo*() const;
65    explicit operator const VkDeviceCreateInfo*() const;
66
67   private:
68    struct ExtensionFilter {
69        VkExtensionProperties* exts;
70        uint32_t ext_count;
71
72        const char** names;
73        uint32_t name_count;
74    };
75
76    VkResult SanitizePNext();
77
78    VkResult SanitizeLayers();
79    VkResult SanitizeExtensions();
80
81    VkResult QueryExtensionCount(uint32_t& count) const;
82    VkResult EnumerateExtensions(uint32_t& count,
83                                 VkExtensionProperties* props) const;
84    VkResult InitExtensionFilter();
85    void FilterExtension(const char* name);
86
87    const bool is_instance_;
88    const VkAllocationCallbacks& allocator_;
89
90    union {
91        const hwvulkan_device_t* hw_dev_;
92        VkPhysicalDevice physical_dev_;
93    };
94
95    union {
96        VkInstanceCreateInfo instance_info_;
97        VkDeviceCreateInfo dev_info_;
98    };
99
100    ExtensionFilter extension_filter_;
101
102    std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
103    std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions_;
104};
105
106CreateInfoWrapper::CreateInfoWrapper(const hwvulkan_device_t* hw_dev,
107                                     const VkInstanceCreateInfo& create_info,
108                                     const VkAllocationCallbacks& allocator)
109    : is_instance_(true),
110      allocator_(allocator),
111      hw_dev_(hw_dev),
112      instance_info_(create_info),
113      extension_filter_() {
114    hook_extensions_.set(ProcHook::EXTENSION_CORE);
115    hal_extensions_.set(ProcHook::EXTENSION_CORE);
116}
117
118CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
119                                     const VkDeviceCreateInfo& create_info,
120                                     const VkAllocationCallbacks& allocator)
121    : is_instance_(false),
122      allocator_(allocator),
123      physical_dev_(physical_dev),
124      dev_info_(create_info),
125      extension_filter_() {
126    hook_extensions_.set(ProcHook::EXTENSION_CORE);
127    hal_extensions_.set(ProcHook::EXTENSION_CORE);
128}
129
130CreateInfoWrapper::~CreateInfoWrapper() {
131    allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
132    allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
133}
134
135VkResult CreateInfoWrapper::Validate() {
136    VkResult result = SanitizePNext();
137    if (result == VK_SUCCESS)
138        result = SanitizeLayers();
139    if (result == VK_SUCCESS)
140        result = SanitizeExtensions();
141
142    return result;
143}
144
145const std::bitset<ProcHook::EXTENSION_COUNT>&
146CreateInfoWrapper::GetHookExtensions() const {
147    return hook_extensions_;
148}
149
150const std::bitset<ProcHook::EXTENSION_COUNT>&
151CreateInfoWrapper::GetHalExtensions() const {
152    return hal_extensions_;
153}
154
155CreateInfoWrapper::operator const VkInstanceCreateInfo*() const {
156    return &instance_info_;
157}
158
159CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
160    return &dev_info_;
161}
162
163VkResult CreateInfoWrapper::SanitizePNext() {
164    const struct StructHeader {
165        VkStructureType type;
166        const void* next;
167    } * header;
168
169    if (is_instance_) {
170        header = reinterpret_cast<const StructHeader*>(instance_info_.pNext);
171
172        // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs
173        while (header &&
174               header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)
175            header = reinterpret_cast<const StructHeader*>(header->next);
176
177        instance_info_.pNext = header;
178    } else {
179        header = reinterpret_cast<const StructHeader*>(dev_info_.pNext);
180
181        // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs
182        while (header &&
183               header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)
184            header = reinterpret_cast<const StructHeader*>(header->next);
185
186        dev_info_.pNext = header;
187    }
188
189    return VK_SUCCESS;
190}
191
192VkResult CreateInfoWrapper::SanitizeLayers() {
193    auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames
194                                       : dev_info_.ppEnabledLayerNames;
195    auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount
196                                       : dev_info_.enabledLayerCount;
197
198    // remove all layers
199    layer_names = nullptr;
200    layer_count = 0;
201
202    return VK_SUCCESS;
203}
204
205VkResult CreateInfoWrapper::SanitizeExtensions() {
206    auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames
207                                     : dev_info_.ppEnabledExtensionNames;
208    auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
209                                     : dev_info_.enabledExtensionCount;
210    if (!ext_count)
211        return VK_SUCCESS;
212
213    VkResult result = InitExtensionFilter();
214    if (result != VK_SUCCESS)
215        return result;
216
217    for (uint32_t i = 0; i < ext_count; i++)
218        FilterExtension(ext_names[i]);
219
220    ext_names = extension_filter_.names;
221    ext_count = extension_filter_.name_count;
222
223    return VK_SUCCESS;
224}
225
226VkResult CreateInfoWrapper::QueryExtensionCount(uint32_t& count) const {
227    if (is_instance_) {
228        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
229                                                             nullptr);
230    } else {
231        const auto& driver = GetData(physical_dev_).driver;
232        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
233                                                         &count, nullptr);
234    }
235}
236
237VkResult CreateInfoWrapper::EnumerateExtensions(
238    uint32_t& count,
239    VkExtensionProperties* props) const {
240    if (is_instance_) {
241        return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
242                                                             props);
243    } else {
244        const auto& driver = GetData(physical_dev_).driver;
245        return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
246                                                         &count, props);
247    }
248}
249
250VkResult CreateInfoWrapper::InitExtensionFilter() {
251    // query extension count
252    uint32_t count;
253    VkResult result = QueryExtensionCount(count);
254    if (result != VK_SUCCESS || count == 0)
255        return result;
256
257    auto& filter = extension_filter_;
258    filter.exts =
259        reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
260            allocator_.pUserData, sizeof(VkExtensionProperties) * count,
261            alignof(VkExtensionProperties),
262            VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
263    if (!filter.exts)
264        return VK_ERROR_OUT_OF_HOST_MEMORY;
265
266    // enumerate extensions
267    result = EnumerateExtensions(count, filter.exts);
268    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
269        return result;
270
271    if (!count)
272        return VK_SUCCESS;
273
274    filter.ext_count = count;
275
276    // allocate name array
277    uint32_t enabled_ext_count = (is_instance_)
278                                     ? instance_info_.enabledExtensionCount
279                                     : dev_info_.enabledExtensionCount;
280    count = std::min(filter.ext_count, enabled_ext_count);
281    filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
282        allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
283        VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
284    if (!filter.names)
285        return VK_ERROR_OUT_OF_HOST_MEMORY;
286
287    return VK_SUCCESS;
288}
289
290void CreateInfoWrapper::FilterExtension(const char* name) {
291    auto& filter = extension_filter_;
292
293    ProcHook::Extension ext_bit = GetProcHookExtension(name);
294    if (is_instance_) {
295        switch (ext_bit) {
296            case ProcHook::KHR_android_surface:
297            case ProcHook::KHR_surface:
298                hook_extensions_.set(ext_bit);
299                // return now as these extensions do not require HAL support
300                return;
301            case ProcHook::EXT_debug_report:
302                // both we and HAL can take part in
303                hook_extensions_.set(ext_bit);
304                break;
305            case ProcHook::EXTENSION_UNKNOWN:
306                // HAL's extensions
307                break;
308            default:
309                ALOGW("Ignored invalid instance extension %s", name);
310                return;
311        }
312    } else {
313        switch (ext_bit) {
314            case ProcHook::KHR_swapchain:
315                // map VK_KHR_swapchain to VK_ANDROID_native_buffer
316                name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
317                ext_bit = ProcHook::ANDROID_native_buffer;
318                break;
319            case ProcHook::EXTENSION_UNKNOWN:
320                // HAL's extensions
321                break;
322            default:
323                ALOGW("Ignored invalid device extension %s", name);
324                return;
325        }
326    }
327
328    for (uint32_t i = 0; i < filter.ext_count; i++) {
329        const VkExtensionProperties& props = filter.exts[i];
330        // ignore unknown extensions
331        if (strcmp(name, props.extensionName) != 0)
332            continue;
333
334        filter.names[filter.name_count++] = name;
335        if (ext_bit != ProcHook::EXTENSION_UNKNOWN) {
336            if (ext_bit == ProcHook::ANDROID_native_buffer)
337                hook_extensions_.set(ProcHook::KHR_swapchain);
338
339            hal_extensions_.set(ext_bit);
340        }
341
342        break;
343    }
344}
345
346const hwvulkan_device_t* g_hwdevice = nullptr;
347
348VKAPI_ATTR void* DefaultAllocate(void*,
349                                 size_t size,
350                                 size_t alignment,
351                                 VkSystemAllocationScope) {
352    void* ptr = nullptr;
353    // Vulkan requires 'alignment' to be a power of two, but posix_memalign
354    // additionally requires that it be at least sizeof(void*).
355    int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
356    ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
357                    ret, ptr);
358    return ret == 0 ? ptr : nullptr;
359}
360
361VKAPI_ATTR void* DefaultReallocate(void*,
362                                   void* ptr,
363                                   size_t size,
364                                   size_t alignment,
365                                   VkSystemAllocationScope) {
366    if (size == 0) {
367        free(ptr);
368        return nullptr;
369    }
370
371    // TODO(jessehall): Right now we never shrink allocations; if the new
372    // request is smaller than the existing chunk, we just continue using it.
373    // Right now the loader never reallocs, so this doesn't matter. If that
374    // changes, or if this code is copied into some other project, this should
375    // probably have a heuristic to allocate-copy-free when doing so will save
376    // "enough" space.
377    size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
378    if (size <= old_size)
379        return ptr;
380
381    void* new_ptr = nullptr;
382    if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
383        return nullptr;
384    if (ptr) {
385        memcpy(new_ptr, ptr, std::min(old_size, size));
386        free(ptr);
387    }
388    return new_ptr;
389}
390
391VKAPI_ATTR void DefaultFree(void*, void* ptr) {
392    ALOGD_CALLSTACK("Free: %p", ptr);
393    free(ptr);
394}
395
396InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
397    void* data_mem = allocator.pfnAllocation(
398        allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
399        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
400    if (!data_mem)
401        return nullptr;
402
403    return new (data_mem) InstanceData(allocator);
404}
405
406void FreeInstanceData(InstanceData* data,
407                      const VkAllocationCallbacks& allocator) {
408    data->~InstanceData();
409    allocator.pfnFree(allocator.pUserData, data);
410}
411
412DeviceData* AllocateDeviceData(
413    const VkAllocationCallbacks& allocator,
414    const DebugReportCallbackList& debug_report_callbacks) {
415    void* data_mem = allocator.pfnAllocation(
416        allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
417        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
418    if (!data_mem)
419        return nullptr;
420
421    return new (data_mem) DeviceData(allocator, debug_report_callbacks);
422}
423
424void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
425    data->~DeviceData();
426    allocator.pfnFree(allocator.pUserData, data);
427}
428
429}  // anonymous namespace
430
431bool Debuggable() {
432    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
433}
434
435bool OpenHAL() {
436    ALOG_ASSERT(!g_hwdevice, "OpenHAL called more than once");
437
438    // Use a stub device unless we successfully open a real HAL device.
439    g_hwdevice = &stubhal::kDevice;
440
441    const hwvulkan_module_t* module;
442    int result =
443        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
444    if (result != 0) {
445        ALOGV("no Vulkan HAL present, using stub HAL");
446        return true;
447    }
448
449    hwvulkan_device_t* device;
450    result =
451        module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
452                                     reinterpret_cast<hw_device_t**>(&device));
453    if (result != 0) {
454        // Any device with a Vulkan HAL should be able to open the device.
455        ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
456              result);
457        return false;
458    }
459
460    g_hwdevice = device;
461
462    return true;
463}
464
465const VkAllocationCallbacks& GetDefaultAllocator() {
466    static const VkAllocationCallbacks kDefaultAllocCallbacks = {
467        .pUserData = nullptr,
468        .pfnAllocation = DefaultAllocate,
469        .pfnReallocation = DefaultReallocate,
470        .pfnFree = DefaultFree,
471    };
472
473    return kDefaultAllocCallbacks;
474}
475
476PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
477    const ProcHook* hook = GetProcHook(pName);
478    if (!hook)
479        return g_hwdevice->GetInstanceProcAddr(instance, pName);
480
481    if (!instance) {
482        if (hook->type == ProcHook::GLOBAL)
483            return hook->proc;
484
485        // v0 layers expect
486        //
487        //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
488        //
489        // to work.
490        if (strcmp(pName, "vkCreateDevice") == 0)
491            return hook->proc;
492
493        ALOGE(
494            "Invalid use of vkGetInstanceProcAddr to query %s without an "
495            "instance",
496            pName);
497
498        return nullptr;
499    }
500
501    PFN_vkVoidFunction proc;
502
503    switch (hook->type) {
504        case ProcHook::INSTANCE:
505            proc = (GetData(instance).hook_extensions[hook->extension])
506                       ? hook->proc
507                       : nullptr;
508            break;
509        case ProcHook::DEVICE:
510            proc = (hook->extension == ProcHook::EXTENSION_CORE)
511                       ? hook->proc
512                       : hook->checked_proc;
513            break;
514        default:
515            ALOGE(
516                "Invalid use of vkGetInstanceProcAddr to query %s with an "
517                "instance",
518                pName);
519            proc = nullptr;
520            break;
521    }
522
523    return proc;
524}
525
526PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
527    const ProcHook* hook = GetProcHook(pName);
528    if (!hook)
529        return GetData(device).driver.GetDeviceProcAddr(device, pName);
530
531    if (hook->type != ProcHook::DEVICE) {
532        ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
533        return nullptr;
534    }
535
536    return (GetData(device).hook_extensions[hook->extension]) ? hook->proc
537                                                              : nullptr;
538}
539
540VkResult EnumerateInstanceExtensionProperties(
541    const char* pLayerName,
542    uint32_t* pPropertyCount,
543    VkExtensionProperties* pProperties) {
544    static const std::array<VkExtensionProperties, 2> loader_extensions = {{
545        // WSI extensions
546        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
547        {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
548         VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
549    }};
550
551    // enumerate our extensions first
552    if (!pLayerName && pProperties) {
553        uint32_t count = std::min(
554            *pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
555
556        std::copy_n(loader_extensions.begin(), count, pProperties);
557
558        if (count < loader_extensions.size()) {
559            *pPropertyCount = count;
560            return VK_INCOMPLETE;
561        }
562
563        pProperties += count;
564        *pPropertyCount -= count;
565    }
566
567    VkResult result = g_hwdevice->EnumerateInstanceExtensionProperties(
568        pLayerName, pPropertyCount, pProperties);
569
570    if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE))
571        *pPropertyCount += loader_extensions.size();
572
573    return result;
574}
575
576VkResult EnumerateDeviceExtensionProperties(
577    VkPhysicalDevice physicalDevice,
578    const char* pLayerName,
579    uint32_t* pPropertyCount,
580    VkExtensionProperties* pProperties) {
581    const InstanceData& data = GetData(physicalDevice);
582
583    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
584        physicalDevice, pLayerName, pPropertyCount, pProperties);
585    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
586        return result;
587
588    if (!pProperties)
589        return result;
590
591    // map VK_ANDROID_native_buffer to VK_KHR_swapchain
592    for (uint32_t i = 0; i < *pPropertyCount; i++) {
593        auto& prop = pProperties[i];
594
595        if (strcmp(prop.extensionName,
596                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
597            continue;
598
599        memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
600               sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
601        prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION;
602    }
603
604    return result;
605}
606
607VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
608                        const VkAllocationCallbacks* pAllocator,
609                        VkInstance* pInstance) {
610    const VkAllocationCallbacks& data_allocator =
611        (pAllocator) ? *pAllocator : GetDefaultAllocator();
612
613    CreateInfoWrapper wrapper(g_hwdevice, *pCreateInfo, data_allocator);
614    VkResult result = wrapper.Validate();
615    if (result != VK_SUCCESS)
616        return result;
617
618    InstanceData* data = AllocateInstanceData(data_allocator);
619    if (!data)
620        return VK_ERROR_OUT_OF_HOST_MEMORY;
621
622    data->hook_extensions |= wrapper.GetHookExtensions();
623
624    // call into the driver
625    VkInstance instance;
626    result = g_hwdevice->CreateInstance(
627        static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
628        &instance);
629    if (result != VK_SUCCESS) {
630        FreeInstanceData(data, data_allocator);
631        return result;
632    }
633
634    // initialize InstanceDriverTable
635    if (!SetData(instance, *data) ||
636        !InitDriverTable(instance, g_hwdevice->GetInstanceProcAddr,
637                         wrapper.GetHalExtensions())) {
638        data->driver.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
639            g_hwdevice->GetInstanceProcAddr(instance, "vkDestroyInstance"));
640        if (data->driver.DestroyInstance)
641            data->driver.DestroyInstance(instance, pAllocator);
642
643        FreeInstanceData(data, data_allocator);
644
645        return VK_ERROR_INCOMPATIBLE_DRIVER;
646    }
647
648    data->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
649        g_hwdevice->GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
650    if (!data->get_device_proc_addr) {
651        data->driver.DestroyInstance(instance, pAllocator);
652        FreeInstanceData(data, data_allocator);
653
654        return VK_ERROR_INCOMPATIBLE_DRIVER;
655    }
656
657    *pInstance = instance;
658
659    return VK_SUCCESS;
660}
661
662void DestroyInstance(VkInstance instance,
663                     const VkAllocationCallbacks* pAllocator) {
664    InstanceData& data = GetData(instance);
665    data.driver.DestroyInstance(instance, pAllocator);
666
667    VkAllocationCallbacks local_allocator;
668    if (!pAllocator) {
669        local_allocator = data.allocator;
670        pAllocator = &local_allocator;
671    }
672
673    FreeInstanceData(&data, *pAllocator);
674}
675
676VkResult CreateDevice(VkPhysicalDevice physicalDevice,
677                      const VkDeviceCreateInfo* pCreateInfo,
678                      const VkAllocationCallbacks* pAllocator,
679                      VkDevice* pDevice) {
680    const InstanceData& instance_data = GetData(physicalDevice);
681    const VkAllocationCallbacks& data_allocator =
682        (pAllocator) ? *pAllocator : instance_data.allocator;
683
684    CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
685    VkResult result = wrapper.Validate();
686    if (result != VK_SUCCESS)
687        return result;
688
689    DeviceData* data = AllocateDeviceData(data_allocator,
690                                          instance_data.debug_report_callbacks);
691    if (!data)
692        return VK_ERROR_OUT_OF_HOST_MEMORY;
693
694    data->hook_extensions |= wrapper.GetHookExtensions();
695
696    // call into the driver
697    VkDevice dev;
698    result = instance_data.driver.CreateDevice(
699        physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
700        pAllocator, &dev);
701    if (result != VK_SUCCESS) {
702        FreeDeviceData(data, data_allocator);
703        return result;
704    }
705
706    // initialize DeviceDriverTable
707    if (!SetData(dev, *data) ||
708        !InitDriverTable(dev, instance_data.get_device_proc_addr,
709                         wrapper.GetHalExtensions())) {
710        data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
711            instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
712        if (data->driver.DestroyDevice)
713            data->driver.DestroyDevice(dev, pAllocator);
714
715        FreeDeviceData(data, data_allocator);
716
717        return VK_ERROR_INCOMPATIBLE_DRIVER;
718    }
719
720    *pDevice = dev;
721
722    return VK_SUCCESS;
723}
724
725void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
726    DeviceData& data = GetData(device);
727    data.driver.DestroyDevice(device, pAllocator);
728
729    VkAllocationCallbacks local_allocator;
730    if (!pAllocator) {
731        local_allocator = data.allocator;
732        pAllocator = &local_allocator;
733    }
734
735    FreeDeviceData(&data, *pAllocator);
736}
737
738VkResult EnumeratePhysicalDevices(VkInstance instance,
739                                  uint32_t* pPhysicalDeviceCount,
740                                  VkPhysicalDevice* pPhysicalDevices) {
741    const auto& data = GetData(instance);
742
743    VkResult result = data.driver.EnumeratePhysicalDevices(
744        instance, pPhysicalDeviceCount, pPhysicalDevices);
745    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) {
746        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++)
747            SetData(pPhysicalDevices[i], data);
748    }
749
750    return result;
751}
752
753void GetDeviceQueue(VkDevice device,
754                    uint32_t queueFamilyIndex,
755                    uint32_t queueIndex,
756                    VkQueue* pQueue) {
757    const auto& data = GetData(device);
758
759    data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
760    SetData(*pQueue, data);
761}
762
763VKAPI_ATTR VkResult
764AllocateCommandBuffers(VkDevice device,
765                       const VkCommandBufferAllocateInfo* pAllocateInfo,
766                       VkCommandBuffer* pCommandBuffers) {
767    const auto& data = GetData(device);
768
769    VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
770                                                         pCommandBuffers);
771    if (result == VK_SUCCESS) {
772        for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
773            SetData(pCommandBuffers[i], data);
774    }
775
776    return result;
777}
778
779}  // namespace driver
780}  // namespace vulkan
781