OSDN Git Service

libvulkan: Use a stub HAL when no real Vulkan HAL is present
[android-x86/frameworks-native.git] / vulkan / libvulkan / driver.cpp
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
44 namespace vulkan {
45 namespace driver {
46
47 namespace {
48
49 class 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
106 CreateInfoWrapper::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
118 CreateInfoWrapper::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
130 CreateInfoWrapper::~CreateInfoWrapper() {
131     allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
132     allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
133 }
134
135 VkResult 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
145 const std::bitset<ProcHook::EXTENSION_COUNT>&
146 CreateInfoWrapper::GetHookExtensions() const {
147     return hook_extensions_;
148 }
149
150 const std::bitset<ProcHook::EXTENSION_COUNT>&
151 CreateInfoWrapper::GetHalExtensions() const {
152     return hal_extensions_;
153 }
154
155 CreateInfoWrapper::operator const VkInstanceCreateInfo*() const {
156     return &instance_info_;
157 }
158
159 CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
160     return &dev_info_;
161 }
162
163 VkResult 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
192 VkResult 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
205 VkResult 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
226 VkResult 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
237 VkResult 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
250 VkResult 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
290 void 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         if (ext_bit == ProcHook::ANDROID_native_buffer)
335             hook_extensions_.set(ProcHook::KHR_swapchain);
336
337         filter.names[filter.name_count++] = name;
338         hal_extensions_.set(ext_bit);
339
340         break;
341     }
342 }
343
344 const hwvulkan_device_t* g_hwdevice = nullptr;
345
346 VKAPI_ATTR void* DefaultAllocate(void*,
347                                  size_t size,
348                                  size_t alignment,
349                                  VkSystemAllocationScope) {
350     void* ptr = nullptr;
351     // Vulkan requires 'alignment' to be a power of two, but posix_memalign
352     // additionally requires that it be at least sizeof(void*).
353     int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
354     ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
355                     ret, ptr);
356     return ret == 0 ? ptr : nullptr;
357 }
358
359 VKAPI_ATTR void* DefaultReallocate(void*,
360                                    void* ptr,
361                                    size_t size,
362                                    size_t alignment,
363                                    VkSystemAllocationScope) {
364     if (size == 0) {
365         free(ptr);
366         return nullptr;
367     }
368
369     // TODO(jessehall): Right now we never shrink allocations; if the new
370     // request is smaller than the existing chunk, we just continue using it.
371     // Right now the loader never reallocs, so this doesn't matter. If that
372     // changes, or if this code is copied into some other project, this should
373     // probably have a heuristic to allocate-copy-free when doing so will save
374     // "enough" space.
375     size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
376     if (size <= old_size)
377         return ptr;
378
379     void* new_ptr = nullptr;
380     if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
381         return nullptr;
382     if (ptr) {
383         memcpy(new_ptr, ptr, std::min(old_size, size));
384         free(ptr);
385     }
386     return new_ptr;
387 }
388
389 VKAPI_ATTR void DefaultFree(void*, void* ptr) {
390     ALOGD_CALLSTACK("Free: %p", ptr);
391     free(ptr);
392 }
393
394 InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
395     void* data_mem = allocator.pfnAllocation(
396         allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
397         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
398     if (!data_mem)
399         return nullptr;
400
401     return new (data_mem) InstanceData(allocator);
402 }
403
404 void FreeInstanceData(InstanceData* data,
405                       const VkAllocationCallbacks& allocator) {
406     data->~InstanceData();
407     allocator.pfnFree(allocator.pUserData, data);
408 }
409
410 DeviceData* AllocateDeviceData(const VkAllocationCallbacks& allocator) {
411     void* data_mem = allocator.pfnAllocation(
412         allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
413         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
414     if (!data_mem)
415         return nullptr;
416
417     return new (data_mem) DeviceData(allocator);
418 }
419
420 void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
421     data->~DeviceData();
422     allocator.pfnFree(allocator.pUserData, data);
423 }
424
425 }  // anonymous namespace
426
427 bool Debuggable() {
428     return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
429 }
430
431 bool OpenHAL() {
432     ALOG_ASSERT(!g_hwdevice, "OpenHAL called more than once");
433
434     // Use a stub device unless we successfully open a real HAL device.
435     g_hwdevice = &stubhal::kDevice;
436
437     const hwvulkan_module_t* module;
438     int result =
439         hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
440     if (result != 0) {
441         ALOGV("no Vulkan HAL present, using stub HAL");
442         return true;
443     }
444
445     hwvulkan_device_t* device;
446     result =
447         module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
448                                      reinterpret_cast<hw_device_t**>(&device));
449     if (result != 0) {
450         // Any device with a Vulkan HAL should be able to open the device.
451         ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
452               result);
453         return false;
454     }
455
456     g_hwdevice = device;
457
458     return true;
459 }
460
461 const VkAllocationCallbacks& GetDefaultAllocator() {
462     static const VkAllocationCallbacks kDefaultAllocCallbacks = {
463         .pUserData = nullptr,
464         .pfnAllocation = DefaultAllocate,
465         .pfnReallocation = DefaultReallocate,
466         .pfnFree = DefaultFree,
467     };
468
469     return kDefaultAllocCallbacks;
470 }
471
472 PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
473     const ProcHook* hook = GetProcHook(pName);
474     if (!hook)
475         return g_hwdevice->GetInstanceProcAddr(instance, pName);
476
477     if (!instance) {
478         if (hook->type == ProcHook::GLOBAL)
479             return hook->proc;
480
481         ALOGE(
482             "Invalid use of vkGetInstanceProcAddr to query %s without an "
483             "instance",
484             pName);
485
486         // Some naughty layers expect
487         //
488         //   vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
489         //
490         // to work.
491         return (strcmp(pName, "vkCreateDevice") == 0) ? hook->proc : nullptr;
492     }
493
494     PFN_vkVoidFunction proc;
495
496     switch (hook->type) {
497         case ProcHook::INSTANCE:
498             proc = (GetData(instance).hook_extensions[hook->extension])
499                        ? hook->proc
500                        : hook->disabled_proc;
501             break;
502         case ProcHook::DEVICE:
503             proc = (hook->extension == ProcHook::EXTENSION_CORE)
504                        ? hook->proc
505                        : hook->checked_proc;
506             break;
507         default:
508             ALOGE(
509                 "Invalid use of vkGetInstanceProcAddr to query %s with an "
510                 "instance",
511                 pName);
512             proc = nullptr;
513             break;
514     }
515
516     return proc;
517 }
518
519 PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
520     const ProcHook* hook = GetProcHook(pName);
521     if (!hook)
522         return GetData(device).driver.GetDeviceProcAddr(device, pName);
523
524     if (hook->type != ProcHook::DEVICE) {
525         ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
526         return nullptr;
527     }
528
529     return (GetData(device).hook_extensions[hook->extension])
530                ? hook->proc
531                : hook->disabled_proc;
532 }
533
534 VkResult EnumerateInstanceExtensionProperties(
535     const char* pLayerName,
536     uint32_t* pPropertyCount,
537     VkExtensionProperties* pProperties) {
538     static const std::array<VkExtensionProperties, 2> loader_extensions = {{
539         // WSI extensions
540         {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
541         {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
542          VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
543     }};
544
545     // enumerate our extensions first
546     if (!pLayerName && pProperties) {
547         uint32_t count = std::min(
548             *pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
549
550         std::copy_n(loader_extensions.begin(), count, pProperties);
551
552         if (count < loader_extensions.size()) {
553             *pPropertyCount = count;
554             return VK_INCOMPLETE;
555         }
556
557         pProperties += count;
558         *pPropertyCount -= count;
559     }
560
561     VkResult result = g_hwdevice->EnumerateInstanceExtensionProperties(
562         pLayerName, pPropertyCount, pProperties);
563
564     if (!pLayerName && (result == VK_SUCCESS || result == VK_INCOMPLETE))
565         *pPropertyCount += loader_extensions.size();
566
567     return result;
568 }
569
570 VkResult EnumerateDeviceExtensionProperties(
571     VkPhysicalDevice physicalDevice,
572     const char* pLayerName,
573     uint32_t* pPropertyCount,
574     VkExtensionProperties* pProperties) {
575     const InstanceData& data = GetData(physicalDevice);
576
577     VkResult result = data.driver.EnumerateDeviceExtensionProperties(
578         physicalDevice, pLayerName, pPropertyCount, pProperties);
579     if (result != VK_SUCCESS && result != VK_INCOMPLETE)
580         return result;
581
582     if (!pProperties)
583         return result;
584
585     // map VK_ANDROID_native_buffer to VK_KHR_swapchain
586     for (uint32_t i = 0; i < *pPropertyCount; i++) {
587         auto& prop = pProperties[i];
588
589         if (strcmp(prop.extensionName,
590                    VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) != 0)
591             continue;
592
593         memcpy(prop.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
594                sizeof(VK_KHR_SWAPCHAIN_EXTENSION_NAME));
595         prop.specVersion = VK_KHR_SWAPCHAIN_SPEC_VERSION;
596     }
597
598     return result;
599 }
600
601 VkResult CreateInstance(const VkInstanceCreateInfo* pCreateInfo,
602                         const VkAllocationCallbacks* pAllocator,
603                         VkInstance* pInstance) {
604     const VkAllocationCallbacks& data_allocator =
605         (pAllocator) ? *pAllocator : GetDefaultAllocator();
606
607     CreateInfoWrapper wrapper(g_hwdevice, *pCreateInfo, data_allocator);
608     VkResult result = wrapper.Validate();
609     if (result != VK_SUCCESS)
610         return result;
611
612     InstanceData* data = AllocateInstanceData(data_allocator);
613     if (!data)
614         return VK_ERROR_OUT_OF_HOST_MEMORY;
615
616     data->hook_extensions |= wrapper.GetHookExtensions();
617     data->hal_extensions |= wrapper.GetHalExtensions();
618
619     // call into the driver
620     VkInstance instance;
621     result = g_hwdevice->CreateInstance(
622         static_cast<const VkInstanceCreateInfo*>(wrapper), pAllocator,
623         &instance);
624     if (result != VK_SUCCESS) {
625         FreeInstanceData(data, data_allocator);
626         return result;
627     }
628
629     // initialize InstanceDriverTable
630     if (!SetData(instance, *data) ||
631         !InitDriverTable(instance, g_hwdevice->GetInstanceProcAddr)) {
632         data->driver.DestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(
633             g_hwdevice->GetInstanceProcAddr(instance, "vkDestroyInstance"));
634         if (data->driver.DestroyInstance)
635             data->driver.DestroyInstance(instance, pAllocator);
636
637         FreeInstanceData(data, data_allocator);
638
639         return VK_ERROR_INCOMPATIBLE_DRIVER;
640     }
641
642     data->get_device_proc_addr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
643         g_hwdevice->GetInstanceProcAddr(instance, "vkGetDeviceProcAddr"));
644     if (!data->get_device_proc_addr) {
645         data->driver.DestroyInstance(instance, pAllocator);
646         FreeInstanceData(data, data_allocator);
647
648         return VK_ERROR_INCOMPATIBLE_DRIVER;
649     }
650
651     *pInstance = instance;
652
653     return VK_SUCCESS;
654 }
655
656 void DestroyInstance(VkInstance instance,
657                      const VkAllocationCallbacks* pAllocator) {
658     InstanceData& data = GetData(instance);
659     data.driver.DestroyInstance(instance, pAllocator);
660
661     VkAllocationCallbacks local_allocator;
662     if (!pAllocator) {
663         local_allocator = data.allocator;
664         pAllocator = &local_allocator;
665     }
666
667     FreeInstanceData(&data, *pAllocator);
668 }
669
670 VkResult CreateDevice(VkPhysicalDevice physicalDevice,
671                       const VkDeviceCreateInfo* pCreateInfo,
672                       const VkAllocationCallbacks* pAllocator,
673                       VkDevice* pDevice) {
674     const InstanceData& instance_data = GetData(physicalDevice);
675     const VkAllocationCallbacks& data_allocator =
676         (pAllocator) ? *pAllocator : instance_data.allocator;
677
678     CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
679     VkResult result = wrapper.Validate();
680     if (result != VK_SUCCESS)
681         return result;
682
683     DeviceData* data = AllocateDeviceData(data_allocator);
684     if (!data)
685         return VK_ERROR_OUT_OF_HOST_MEMORY;
686
687     data->hook_extensions |= wrapper.GetHookExtensions();
688     data->hal_extensions |= wrapper.GetHalExtensions();
689
690     // call into the driver
691     VkDevice dev;
692     result = instance_data.driver.CreateDevice(
693         physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
694         pAllocator, &dev);
695     if (result != VK_SUCCESS) {
696         FreeDeviceData(data, data_allocator);
697         return result;
698     }
699
700     // initialize DeviceDriverTable
701     if (!SetData(dev, *data) ||
702         !InitDriverTable(dev, instance_data.get_device_proc_addr)) {
703         data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
704             instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
705         if (data->driver.DestroyDevice)
706             data->driver.DestroyDevice(dev, pAllocator);
707
708         FreeDeviceData(data, data_allocator);
709
710         return VK_ERROR_INCOMPATIBLE_DRIVER;
711     }
712
713     *pDevice = dev;
714
715     return VK_SUCCESS;
716 }
717
718 void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
719     DeviceData& data = GetData(device);
720     data.driver.DestroyDevice(device, pAllocator);
721
722     VkAllocationCallbacks local_allocator;
723     if (!pAllocator) {
724         local_allocator = data.allocator;
725         pAllocator = &local_allocator;
726     }
727
728     FreeDeviceData(&data, *pAllocator);
729 }
730
731 VkResult EnumeratePhysicalDevices(VkInstance instance,
732                                   uint32_t* pPhysicalDeviceCount,
733                                   VkPhysicalDevice* pPhysicalDevices) {
734     const auto& data = GetData(instance);
735
736     VkResult result = data.driver.EnumeratePhysicalDevices(
737         instance, pPhysicalDeviceCount, pPhysicalDevices);
738     if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pPhysicalDevices) {
739         for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++)
740             SetData(pPhysicalDevices[i], data);
741     }
742
743     return result;
744 }
745
746 void GetDeviceQueue(VkDevice device,
747                     uint32_t queueFamilyIndex,
748                     uint32_t queueIndex,
749                     VkQueue* pQueue) {
750     const auto& data = GetData(device);
751
752     data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
753     SetData(*pQueue, data);
754 }
755
756 VKAPI_ATTR VkResult
757 AllocateCommandBuffers(VkDevice device,
758                        const VkCommandBufferAllocateInfo* pAllocateInfo,
759                        VkCommandBuffer* pCommandBuffers) {
760     const auto& data = GetData(device);
761
762     VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
763                                                          pCommandBuffers);
764     if (result == VK_SUCCESS) {
765         for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
766             SetData(pCommandBuffers[i], data);
767     }
768
769     return result;
770 }
771
772 }  // namespace driver
773 }  // namespace vulkan