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