driver.cpp revision 109f8985ceaf746fd04b6fe81be238b3865062b7
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(const VkAllocationCallbacks& allocator) {
413    void* data_mem = allocator.pfnAllocation(
414        allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
415        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
416    if (!data_mem)
417        return nullptr;
418
419    return new (data_mem) DeviceData(allocator);
420}
421
422void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
423    data->~DeviceData();
424    allocator.pfnFree(allocator.pUserData, data);
425}
426
427}  // anonymous namespace
428
429bool Debuggable() {
430    return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
431}
432
433bool OpenHAL() {
434    ALOG_ASSERT(!g_hwdevice, "OpenHAL called more than once");
435
436    // Use a stub device unless we successfully open a real HAL device.
437    g_hwdevice = &stubhal::kDevice;
438
439    const hwvulkan_module_t* module;
440    int result =
441        hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
442    if (result != 0) {
443        ALOGV("no Vulkan HAL present, using stub HAL");
444        return true;
445    }
446
447    hwvulkan_device_t* device;
448    result =
449        module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
450                                     reinterpret_cast<hw_device_t**>(&device));
451    if (result != 0) {
452        // Any device with a Vulkan HAL should be able to open the device.
453        ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
454              result);
455        return false;
456    }
457
458    g_hwdevice = device;
459
460    return true;
461}
462
463const VkAllocationCallbacks& GetDefaultAllocator() {
464    static const VkAllocationCallbacks kDefaultAllocCallbacks = {
465        .pUserData = nullptr,
466        .pfnAllocation = DefaultAllocate,
467        .pfnReallocation = DefaultReallocate,
468        .pfnFree = DefaultFree,
469    };
470
471    return kDefaultAllocCallbacks;
472}
473
474PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
475    const ProcHook* hook = GetProcHook(pName);
476    if (!hook)
477        return g_hwdevice->GetInstanceProcAddr(instance, pName);
478
479    if (!instance) {
480        if (hook->type == ProcHook::GLOBAL)
481            return hook->proc;
482
483        // v0 layers expect
484        //
485        //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
486        //
487        // to work.
488        if (strcmp(pName, "vkCreateDevice") == 0)
489            return hook->proc;
490
491        ALOGE(
492            "Invalid use of vkGetInstanceProcAddr to query %s without an "
493            "instance",
494            pName);
495
496        return nullptr;
497    }
498
499    PFN_vkVoidFunction proc;
500
501    switch (hook->type) {
502        case ProcHook::INSTANCE:
503            proc = (GetData(instance).hook_extensions[hook->extension])
504                       ? hook->proc
505                       : nullptr;
506            break;
507        case ProcHook::DEVICE:
508            proc = (hook->extension == ProcHook::EXTENSION_CORE)
509                       ? hook->proc
510                       : hook->checked_proc;
511            break;
512        default:
513            ALOGE(
514                "Invalid use of vkGetInstanceProcAddr to query %s with an "
515                "instance",
516                pName);
517            proc = nullptr;
518            break;
519    }
520
521    return proc;
522}
523
524PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
525    const ProcHook* hook = GetProcHook(pName);
526    if (!hook)
527        return GetData(device).driver.GetDeviceProcAddr(device, pName);
528
529    if (hook->type != ProcHook::DEVICE) {
530        ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
531        return nullptr;
532    }
533
534    return (GetData(device).hook_extensions[hook->extension]) ? hook->proc
535                                                              : nullptr;
536}
537
538VkResult EnumerateInstanceExtensionProperties(
539    const char* pLayerName,
540    uint32_t* pPropertyCount,
541    VkExtensionProperties* pProperties) {
542    static const std::array<VkExtensionProperties, 2> loader_extensions = {{
543        // WSI extensions
544        {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
545        {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
546         VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
547    }};
548
549    // enumerate our extensions first
550    if (!pLayerName && pProperties) {
551        uint32_t count = std::min(
552            *pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
553
554        std::copy_n(loader_extensions.begin(), count, pProperties);
555
556        if (count < loader_extensions.size()) {
557            *pPropertyCount = count;
558            return VK_INCOMPLETE;
559        }
560
561        pProperties += count;
562        *pPropertyCount -= count;
563    }
564
565    VkResult result = g_hwdevice->EnumerateInstanceExtensionProperties(
566        pLayerName, pPropertyCount, pProperties);
567
568    if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE))
569        *pPropertyCount += loader_extensions.size();
570
571    return result;
572}
573
574VkResult EnumerateDeviceExtensionProperties(
575    VkPhysicalDevice physicalDevice,
576    const char* pLayerName,
577    uint32_t* pPropertyCount,
578    VkExtensionProperties* pProperties) {
579    const InstanceData& data = GetData(physicalDevice);
580
581    VkResult result = data.driver.EnumerateDeviceExtensionProperties(
582        physicalDevice, pLayerName, pPropertyCount, pProperties);
583    if (result != VK_SUCCESS && result != VK_INCOMPLETE)
584        return result;
585
586    if (!pProperties)
587        return result;
588
589    // map VK_ANDROID_native_buffer to VK_KHR_swapchain
590    for (uint32_t i = 0; i < *pPropertyCount; i++) {
591        auto& prop = pProperties[i];
592
593        if (strcmp(prop.extensionName,
594                   VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
595            continue;
596
597        memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
598               sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
599        prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION;
600    }
601
602    return result;
603}
604
605VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
606                        const VkAllocationCallbacks* pAllocator,
607                        VkInstance* pInstance) {
608    const VkAllocationCallbacks& data_allocator =
609        (pAllocator) ? *pAllocator : GetDefaultAllocator();
610
611    CreateInfoWrapper wrapper(g_hwdevice, *pCreateInfo, data_allocator);
612    VkResult result = wrapper.Validate();
613    if (result != VK_SUCCESS)
614        return result;
615
616    InstanceData* data = AllocateInstanceData(data_allocator);
617    if (!data)
618        return VK_ERROR_OUT_OF_HOST_MEMORY;
619
620    data->hook_extensions |= wrapper.GetHookExtensions();
621
622    // call into the driver
623    VkInstance instance;
624    result = g_hwdevice->CreateInstance(
625        static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
626        &instance);
627    if (result != VK_SUCCESS) {
628        FreeInstanceData(data, data_allocator);
629        return result;
630    }
631
632    // initialize InstanceDriverTable
633    if (!SetData(instance, *data) ||
634        !InitDriverTable(instance, g_hwdevice->GetInstanceProcAddr,
635                         wrapper.GetHalExtensions())) {
636        data->driver.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
637            g_hwdevice->GetInstanceProcAddr(instance, "vkDestroyInstance"));
638        if (data->driver.DestroyInstance)
639            data->driver.DestroyInstance(instance, pAllocator);
640
641        FreeInstanceData(data, data_allocator);
642
643        return VK_ERROR_INCOMPATIBLE_DRIVER;
644    }
645
646    data->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
647        g_hwdevice->GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
648    if (!data->get_device_proc_addr) {
649        data->driver.DestroyInstance(instance, pAllocator);
650        FreeInstanceData(data, data_allocator);
651
652        return VK_ERROR_INCOMPATIBLE_DRIVER;
653    }
654
655    *pInstance = instance;
656
657    return VK_SUCCESS;
658}
659
660void DestroyInstance(VkInstance instance,
661                     const VkAllocationCallbacks* pAllocator) {
662    InstanceData& data = GetData(instance);
663    data.driver.DestroyInstance(instance, pAllocator);
664
665    VkAllocationCallbacks local_allocator;
666    if (!pAllocator) {
667        local_allocator = data.allocator;
668        pAllocator = &local_allocator;
669    }
670
671    FreeInstanceData(&data, *pAllocator);
672}
673
674VkResult CreateDevice(VkPhysicalDevice physicalDevice,
675                      const VkDeviceCreateInfo* pCreateInfo,
676                      const VkAllocationCallbacks* pAllocator,
677                      VkDevice* pDevice) {
678    const InstanceData& instance_data = GetData(physicalDevice);
679    const VkAllocationCallbacks& data_allocator =
680        (pAllocator) ? *pAllocator : instance_data.allocator;
681
682    CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
683    VkResult result = wrapper.Validate();
684    if (result != VK_SUCCESS)
685        return result;
686
687    DeviceData* data = AllocateDeviceData(data_allocator);
688    if (!data)
689        return VK_ERROR_OUT_OF_HOST_MEMORY;
690
691    data->hook_extensions |= wrapper.GetHookExtensions();
692
693    // call into the driver
694    VkDevice dev;
695    result = instance_data.driver.CreateDevice(
696        physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
697        pAllocator, &dev);
698    if (result != VK_SUCCESS) {
699        FreeDeviceData(data, data_allocator);
700        return result;
701    }
702
703    // initialize DeviceDriverTable
704    if (!SetData(dev, *data) ||
705        !InitDriverTable(dev, instance_data.get_device_proc_addr,
706                         wrapper.GetHalExtensions())) {
707        data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
708            instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
709        if (data->driver.DestroyDevice)
710            data->driver.DestroyDevice(dev, pAllocator);
711
712        FreeDeviceData(data, data_allocator);
713
714        return VK_ERROR_INCOMPATIBLE_DRIVER;
715    }
716
717    *pDevice = dev;
718
719    return VK_SUCCESS;
720}
721
722void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
723    DeviceData& data = GetData(device);
724    data.driver.DestroyDevice(device, pAllocator);
725
726    VkAllocationCallbacks local_allocator;
727    if (!pAllocator) {
728        local_allocator = data.allocator;
729        pAllocator = &local_allocator;
730    }
731
732    FreeDeviceData(&data, *pAllocator);
733}
734
735VkResult EnumeratePhysicalDevices(VkInstance instance,
736                                  uint32_t* pPhysicalDeviceCount,
737                                  VkPhysicalDevice* pPhysicalDevices) {
738    const auto& data = GetData(instance);
739
740    VkResult result = data.driver.EnumeratePhysicalDevices(
741        instance, pPhysicalDeviceCount, pPhysicalDevices);
742    if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) {
743        for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++)
744            SetData(pPhysicalDevices[i], data);
745    }
746
747    return result;
748}
749
750void GetDeviceQueue(VkDevice device,
751                    uint32_t queueFamilyIndex,
752                    uint32_t queueIndex,
753                    VkQueue* pQueue) {
754    const auto& data = GetData(device);
755
756    data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
757    SetData(*pQueue, data);
758}
759
760VKAPI_ATTR VkResult
761AllocateCommandBuffers(VkDevice device,
762                       const VkCommandBufferAllocateInfo* pAllocateInfo,
763                       VkCommandBuffer* pCommandBuffers) {
764    const auto& data = GetData(device);
765
766    VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
767                                                         pCommandBuffers);
768    if (result == VK_SUCCESS) {
769        for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
770            SetData(pCommandBuffers[i], data);
771    }
772
773    return result;
774}
775
776}  // namespace driver
777}  // namespace vulkan
778