blob: 19ca9f22b0374bdffc999a1e272f73be6dd8eb4e [file] [log] [blame]
Jesse Hall04f4f472015-08-16 19:51:04 -07001// module header
2#include "loader.h"
3// standard C headers
4#include <inttypes.h>
5#include <malloc.h>
6#include <pthread.h>
7#include <string.h>
8// standard C++ headers
9#include <algorithm>
10#include <mutex>
11// platform/library headers
12#include <hardware/hwvulkan.h>
13#include <log/log.h>
14
15using namespace vulkan;
16
17static const uint32_t kMaxPhysicalDevices = 4;
18
19struct VkInstance_T {
20 VkInstance_T(const VkAllocCallbacks* alloc_callbacks)
21 : vtbl(&vtbl_storage), alloc(alloc_callbacks), num_physical_devices(0) {
22 memset(&vtbl_storage, 0, sizeof(vtbl_storage));
23 memset(physical_devices, 0, sizeof(physical_devices));
24 memset(&drv.vtbl, 0, sizeof(drv.vtbl));
25 drv.GetDeviceProcAddr = nullptr;
26 drv.num_physical_devices = 0;
27 }
28
29 InstanceVtbl* vtbl;
30 InstanceVtbl vtbl_storage;
31
32 const VkAllocCallbacks* alloc;
33 uint32_t num_physical_devices;
34 VkPhysicalDevice physical_devices[kMaxPhysicalDevices];
35
36 struct Driver {
37 // Pointers to driver entry points. Used explicitly by the loader; not
38 // set as the dispatch table for any objects.
39 InstanceVtbl vtbl;
40
41 // Pointer to the driver's get_device_proc_addr, must be valid for any
42 // of the driver's physical devices. Not part of the InstanceVtbl since
43 // it's not an Instance/PhysicalDevice function.
44 PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
45
46 // Number of physical devices owned by this driver.
47 uint32_t num_physical_devices;
48 } drv; // may eventually be an array
49};
50
51// -----------------------------------------------------------------------------
52
53namespace {
54
55typedef VkInstance_T Instance;
56
57struct Device {
58 Device(const VkAllocCallbacks* alloc_callbacks) : alloc(alloc_callbacks) {
59 memset(&vtbl_storage, 0, sizeof(vtbl_storage));
60 vtbl_storage.device = this;
61 }
62 DeviceVtbl vtbl_storage;
63 const VkAllocCallbacks* alloc;
64};
65
66// -----------------------------------------------------------------------------
67// Utility Code
68
69inline const InstanceVtbl* GetVtbl(VkPhysicalDevice physicalDevice) {
70 return *reinterpret_cast<InstanceVtbl**>(physicalDevice);
71}
72
73inline const DeviceVtbl* GetVtbl(VkDevice device) {
74 return *reinterpret_cast<DeviceVtbl**>(device);
75}
76
77void* DefaultAlloc(void*, size_t size, size_t alignment, VkSystemAllocType) {
78 return memalign(alignment, size);
79}
80
81void DefaultFree(void*, void* pMem) {
82 free(pMem);
83}
84
85const VkAllocCallbacks kDefaultAllocCallbacks = {
86 .pUserData = nullptr,
87 .pfnAlloc = DefaultAlloc,
88 .pfnFree = DefaultFree,
89};
90
91hwvulkan_device_t* g_hwdevice;
92bool EnsureInitialized() {
93 static std::once_flag once_flag;
94 static const hwvulkan_module_t* module;
95
96 std::call_once(once_flag, []() {
97 int result;
98 result = hw_get_module("vulkan",
99 reinterpret_cast<const hw_module_t**>(&module));
100 if (result != 0) {
101 ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result),
102 result);
103 return;
104 }
105 result = module->common.methods->open(
106 &module->common, HWVULKAN_DEVICE_0,
107 reinterpret_cast<hw_device_t**>(&g_hwdevice));
108 if (result != 0) {
109 ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result),
110 result);
111 module = nullptr;
112 return;
113 }
114 });
115
116 return module != nullptr && g_hwdevice != nullptr;
117}
118
119void DestroyDevice(Device* device) {
120 const VkAllocCallbacks* alloc = device->alloc;
121 device->~Device();
122 alloc->pfnFree(alloc->pUserData, device);
123}
124
125// -----------------------------------------------------------------------------
126// "Bottom" functions. These are called at the end of the instance dispatch
127// chain.
128
129VkResult DestroyInstanceBottom(VkInstance instance) {
130 // These checks allow us to call DestroyInstanceBottom from any error path
131 // in CreateInstanceBottom, before the driver instance is fully initialized.
132 if (instance->drv.vtbl.instance != VK_NULL_HANDLE &&
133 instance->drv.vtbl.DestroyInstance) {
134 instance->drv.vtbl.DestroyInstance(instance->drv.vtbl.instance);
135 }
136 const VkAllocCallbacks* alloc = instance->alloc;
137 instance->~VkInstance_T();
138 alloc->pfnFree(alloc->pUserData, instance);
139 return VK_SUCCESS;
140}
141
142VkResult CreateInstanceBottom(const VkInstanceCreateInfo* create_info,
143 VkInstance* instance_ptr) {
144 Instance* instance = *instance_ptr;
145 VkResult result;
146
147 result =
148 g_hwdevice->CreateInstance(create_info, &instance->drv.vtbl.instance);
149 if (result != VK_SUCCESS) {
150 DestroyInstanceBottom(instance);
151 return result;
152 }
153
154 if (!LoadInstanceVtbl(instance->drv.vtbl.instance,
155 g_hwdevice->GetInstanceProcAddr,
156 instance->drv.vtbl)) {
157 DestroyInstanceBottom(instance);
158 return VK_ERROR_INITIALIZATION_FAILED;
159 }
160
161 // vkGetDeviceProcAddr has a bootstrapping problem. We require that it be
162 // queryable from the Instance, and that the resulting function work for any
163 // VkDevice created from the instance.
164 instance->drv.GetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(
165 g_hwdevice->GetInstanceProcAddr(instance->drv.vtbl.instance,
166 "vkGetDeviceProcAddr"));
167 if (!instance->drv.GetDeviceProcAddr) {
168 ALOGE("missing instance proc: \"%s\"", "vkGetDeviceProcAddr");
169 DestroyInstanceBottom(instance);
170 return VK_ERROR_INITIALIZATION_FAILED;
171 }
172
173 hwvulkan_dispatch_t* dispatch =
174 reinterpret_cast<hwvulkan_dispatch_t*>(instance->drv.vtbl.instance);
175 if (dispatch->magic == HWVULKAN_DISPATCH_MAGIC) {
176 // Skip setting dispatch->vtbl on the driver instance handle, since we
177 // never intentionally call through it; we go through Instance::drv.vtbl
178 // instead.
179 } else {
180 ALOGE("invalid VkInstance dispatch magic: 0x%" PRIxPTR,
181 dispatch->magic);
182 DestroyInstanceBottom(instance);
183 return VK_ERROR_INITIALIZATION_FAILED;
184 }
185
186 uint32_t num_physical_devices = 0;
187 result = instance->drv.vtbl.EnumeratePhysicalDevices(
188 instance->drv.vtbl.instance, &num_physical_devices, nullptr);
189 if (result != VK_SUCCESS) {
190 DestroyInstanceBottom(instance);
191 return VK_ERROR_INITIALIZATION_FAILED;
192 }
193 num_physical_devices = std::min(num_physical_devices, kMaxPhysicalDevices);
194 result = instance->drv.vtbl.EnumeratePhysicalDevices(
195 instance->drv.vtbl.instance, &num_physical_devices,
196 instance->physical_devices);
197 if (result != VK_SUCCESS) {
198 DestroyInstanceBottom(instance);
199 return VK_ERROR_INITIALIZATION_FAILED;
200 }
201 for (uint32_t i = 0; i < num_physical_devices; i++) {
202 dispatch = reinterpret_cast<hwvulkan_dispatch_t*>(
203 instance->physical_devices[i]);
204 if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
205 ALOGE("invalid VkPhysicalDevice dispatch magic: 0x%" PRIxPTR,
206 dispatch->magic);
207 DestroyInstanceBottom(instance);
208 return VK_ERROR_INITIALIZATION_FAILED;
209 }
210 dispatch->vtbl = instance->vtbl;
211 }
212 instance->drv.num_physical_devices = num_physical_devices;
213
214 instance->num_physical_devices = instance->drv.num_physical_devices;
215 return VK_SUCCESS;
216}
217
218VkResult EnumeratePhysicalDevicesBottom(VkInstance instance,
219 uint32_t* pdev_count,
220 VkPhysicalDevice* pdevs) {
221 uint32_t count = instance->num_physical_devices;
222 if (pdevs) {
223 count = std::min(count, *pdev_count);
224 std::copy(instance->physical_devices,
225 instance->physical_devices + count, pdevs);
226 }
227 *pdev_count = count;
228 return VK_SUCCESS;
229}
230
231VkResult GetPhysicalDeviceFeaturesBottom(VkPhysicalDevice pdev,
232 VkPhysicalDeviceFeatures* features) {
233 return GetVtbl(pdev)
234 ->instance->drv.vtbl.GetPhysicalDeviceFeatures(pdev, features);
235}
236
237VkResult GetPhysicalDeviceFormatPropertiesBottom(
238 VkPhysicalDevice pdev,
239 VkFormat format,
240 VkFormatProperties* properties) {
241 return GetVtbl(pdev)->instance->drv.vtbl.GetPhysicalDeviceFormatProperties(
242 pdev, format, properties);
243}
244
245VkResult GetPhysicalDeviceImageFormatPropertiesBottom(
246 VkPhysicalDevice pdev,
247 VkFormat format,
248 VkImageType type,
249 VkImageTiling tiling,
250 VkImageUsageFlags usage,
251 VkImageFormatProperties* properties) {
252 return GetVtbl(pdev)
253 ->instance->drv.vtbl.GetPhysicalDeviceImageFormatProperties(
254 pdev, format, type, tiling, usage, properties);
255}
256
257VkResult GetPhysicalDeviceLimitsBottom(VkPhysicalDevice pdev,
258 VkPhysicalDeviceLimits* limits) {
259 return GetVtbl(pdev)
260 ->instance->drv.vtbl.GetPhysicalDeviceLimits(pdev, limits);
261}
262
263VkResult GetPhysicalDevicePropertiesBottom(
264 VkPhysicalDevice pdev,
265 VkPhysicalDeviceProperties* properties) {
266 return GetVtbl(pdev)
267 ->instance->drv.vtbl.GetPhysicalDeviceProperties(pdev, properties);
268}
269
270VkResult GetPhysicalDeviceQueueCountBottom(VkPhysicalDevice pdev,
271 uint32_t* count) {
272 return GetVtbl(pdev)
273 ->instance->drv.vtbl.GetPhysicalDeviceQueueCount(pdev, count);
274}
275
276VkResult GetPhysicalDeviceQueuePropertiesBottom(
277 VkPhysicalDevice pdev,
278 uint32_t count,
279 VkPhysicalDeviceQueueProperties* properties) {
280 return GetVtbl(pdev)->instance->drv.vtbl.GetPhysicalDeviceQueueProperties(
281 pdev, count, properties);
282}
283
284VkResult GetPhysicalDeviceMemoryPropertiesBottom(
285 VkPhysicalDevice pdev,
286 VkPhysicalDeviceMemoryProperties* properties) {
287 return GetVtbl(pdev)->instance->drv.vtbl.GetPhysicalDeviceMemoryProperties(
288 pdev, properties);
289}
290
291VkResult CreateDeviceBottom(VkPhysicalDevice pdev,
292 const VkDeviceCreateInfo* create_info,
293 VkDevice* out_device) {
294 const Instance& instance = *static_cast<Instance*>(GetVtbl(pdev)->instance);
295 VkResult result;
296
297 void* mem = instance.alloc->pfnAlloc(instance.alloc->pUserData,
298 sizeof(Device), alignof(Device),
299 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
300 if (!mem)
301 return VK_ERROR_OUT_OF_HOST_MEMORY;
302 Device* device = new (mem) Device(instance.alloc);
303
304 VkDevice drv_device;
305 result = instance.drv.vtbl.CreateDevice(pdev, create_info, &drv_device);
306 if (result != VK_SUCCESS) {
307 DestroyDevice(device);
308 return result;
309 }
310
311 if (!LoadDeviceVtbl(drv_device, instance.drv.GetDeviceProcAddr,
312 device->vtbl_storage)) {
313 if (device->vtbl_storage.DestroyDevice)
314 device->vtbl_storage.DestroyDevice(drv_device);
315 DestroyDevice(device);
316 return VK_ERROR_INITIALIZATION_FAILED;
317 }
318
319 hwvulkan_dispatch_t* dispatch =
320 reinterpret_cast<hwvulkan_dispatch_t*>(drv_device);
321 if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
322 ALOGE("invalid VkDevice dispatch magic: 0x%" PRIxPTR, dispatch->magic);
323 device->vtbl_storage.DestroyDevice(drv_device);
324 DestroyDevice(device);
325 return VK_ERROR_INITIALIZATION_FAILED;
326 }
327 dispatch->vtbl = &device->vtbl_storage;
328
329 // TODO: insert device layer entry points into device->vtbl_storage here?
330
331 *out_device = drv_device;
332 return VK_SUCCESS;
333}
334
335VkResult GetPhysicalDeviceExtensionPropertiesBottom(
336 VkPhysicalDevice pdev,
337 const char* layer_name,
338 uint32_t* properties_count,
339 VkExtensionProperties* properties) {
340 // TODO: what are we supposed to do with layer_name here?
341 return GetVtbl(pdev)
342 ->instance->drv.vtbl.GetPhysicalDeviceExtensionProperties(
343 pdev, layer_name, properties_count, properties);
344}
345
346VkResult GetPhysicalDeviceLayerPropertiesBottom(VkPhysicalDevice pdev,
347 uint32_t* properties_count,
348 VkLayerProperties* properties) {
349 return GetVtbl(pdev)->instance->drv.vtbl.GetPhysicalDeviceLayerProperties(
350 pdev, properties_count, properties);
351}
352
353VkResult GetPhysicalDeviceSparseImageFormatPropertiesBottom(
354 VkPhysicalDevice pdev,
355 VkFormat format,
356 VkImageType type,
357 uint32_t samples,
358 VkImageUsageFlags usage,
359 VkImageTiling tiling,
360 uint32_t* properties_count,
361 VkSparseImageFormatProperties* properties) {
362 return GetVtbl(pdev)
363 ->instance->drv.vtbl.GetPhysicalDeviceSparseImageFormatProperties(
364 pdev, format, type, samples, usage, tiling, properties_count,
365 properties);
366}
367
368PFN_vkVoidFunction GetInstanceProcAddrBottom(VkInstance, const char*);
369
370const InstanceVtbl kBottomInstanceFunctions = {
371 // clang-format off
372 .instance = nullptr,
373 .CreateInstance = CreateInstanceBottom,
374 .DestroyInstance = DestroyInstanceBottom,
375 .GetInstanceProcAddr = GetInstanceProcAddrBottom,
376 .EnumeratePhysicalDevices = EnumeratePhysicalDevicesBottom,
377 .GetPhysicalDeviceFeatures = GetPhysicalDeviceFeaturesBottom,
378 .GetPhysicalDeviceFormatProperties = GetPhysicalDeviceFormatPropertiesBottom,
379 .GetPhysicalDeviceImageFormatProperties = GetPhysicalDeviceImageFormatPropertiesBottom,
380 .GetPhysicalDeviceLimits = GetPhysicalDeviceLimitsBottom,
381 .GetPhysicalDeviceProperties = GetPhysicalDevicePropertiesBottom,
382 .GetPhysicalDeviceQueueCount = GetPhysicalDeviceQueueCountBottom,
383 .GetPhysicalDeviceQueueProperties = GetPhysicalDeviceQueuePropertiesBottom,
384 .GetPhysicalDeviceMemoryProperties = GetPhysicalDeviceMemoryPropertiesBottom,
385 .CreateDevice = CreateDeviceBottom,
386 .GetPhysicalDeviceExtensionProperties = GetPhysicalDeviceExtensionPropertiesBottom,
387 .GetPhysicalDeviceLayerProperties = GetPhysicalDeviceLayerPropertiesBottom,
388 .GetPhysicalDeviceSparseImageFormatProperties = GetPhysicalDeviceSparseImageFormatPropertiesBottom,
389 // clang-format on
390};
391
392PFN_vkVoidFunction GetInstanceProcAddrBottom(VkInstance, const char* name) {
393 // The bottom GetInstanceProcAddr is only called by the innermost layer,
394 // when there is one, when it initializes its own dispatch table.
395 return GetSpecificInstanceProcAddr(&kBottomInstanceFunctions, name);
396}
397
398} // namespace
399
400// -----------------------------------------------------------------------------
401// Global functions. These are called directly from the loader entry points,
402// without going through a dispatch table.
403
404namespace vulkan {
405
406VkResult GetGlobalExtensionProperties(const char* /*layer_name*/,
407 uint32_t* count,
408 VkExtensionProperties* /*properties*/) {
409 if (!count)
410 return VK_ERROR_INVALID_POINTER;
411 if (!EnsureInitialized())
412 return VK_ERROR_UNAVAILABLE;
413
414 // TODO: not yet implemented
415 ALOGW("vkGetGlobalExtensionProperties not implemented");
416
417 *count = 0;
418 return VK_SUCCESS;
419}
420
421VkResult GetGlobalLayerProperties(uint32_t* count,
422 VkLayerProperties* /*properties*/) {
423 if (!count)
424 return VK_ERROR_INVALID_POINTER;
425 if (!EnsureInitialized())
426 return VK_ERROR_UNAVAILABLE;
427
428 // TODO: not yet implemented
429 ALOGW("vkGetGlobalLayerProperties not implemented");
430
431 *count = 0;
432 return VK_SUCCESS;
433}
434
435VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
436 VkInstance* out_instance) {
437 VkResult result;
438
439 if (!EnsureInitialized())
440 return VK_ERROR_UNAVAILABLE;
441
442 VkInstanceCreateInfo local_create_info = *create_info;
443 if (!local_create_info.pAllocCb)
444 local_create_info.pAllocCb = &kDefaultAllocCallbacks;
445 create_info = &local_create_info;
446
447 void* instance_mem = create_info->pAllocCb->pfnAlloc(
448 create_info->pAllocCb->pUserData, sizeof(Instance), alignof(Instance),
449 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
450 if (!instance_mem)
451 return VK_ERROR_OUT_OF_HOST_MEMORY;
452 Instance* instance = new (instance_mem) Instance(create_info->pAllocCb);
453
454 instance->vtbl_storage = kBottomInstanceFunctions;
455 instance->vtbl_storage.instance = instance;
456
457 // TODO: Insert enabled layers into instance->dispatch_vtbl here.
458
459 // TODO: We'll want to call CreateInstance through the dispatch table
460 // instead of calling the loader's terminator
461 *out_instance = instance;
462 result = CreateInstanceBottom(create_info, out_instance);
463 if (result <= 0) {
464 // For every layer, including the loader top and bottom layers:
465 // - If a call to the next CreateInstance fails, the layer must clean
466 // up anything it has successfully done so far, and propagate the
467 // error upwards.
468 // - If a layer successfully calls the next layer's CreateInstance, and
469 // afterwards must fail for some reason, it must call the next layer's
470 // DestroyInstance before returning.
471 // - The layer must not call the next layer's DestroyInstance if that
472 // layer's CreateInstance wasn't called, or returned failure.
473
474 // On failure, CreateInstanceBottom frees the instance struct, so it's
475 // already gone at this point. Nothing to do.
476 }
477
478 return result;
479}
480
481PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
482 if (!instance)
483 return GetGlobalInstanceProcAddr(name);
484 // For special-case functions we always return the loader entry
485 if (strcmp(name, "vkGetInstanceProcAddr") == 0 ||
486 strcmp(name, "vkGetDeviceProcAddr") == 0) {
487 return GetGlobalInstanceProcAddr(name);
488 }
489 return GetSpecificInstanceProcAddr(instance->vtbl, name);
490}
491
492PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
493 if (!device)
494 return GetGlobalDeviceProcAddr(name);
495 // For special-case functions we always return the loader entry
496 if (strcmp(name, "vkGetDeviceQueue") == 0 ||
Jesse Hallc7a6eb52015-08-31 12:52:03 -0700497 strcmp(name, "vkCreateCommandBuffer") == 0 ||
Jesse Hall04f4f472015-08-16 19:51:04 -0700498 strcmp(name, "vkDestroyDevice") == 0) {
499 return GetGlobalDeviceProcAddr(name);
500 }
501 return GetSpecificDeviceProcAddr(GetVtbl(device), name);
502}
503
504VkResult GetDeviceQueue(VkDevice drv_device,
505 uint32_t family,
506 uint32_t index,
507 VkQueue* out_queue) {
508 VkResult result;
509 VkQueue queue;
510 const DeviceVtbl* vtbl = GetVtbl(drv_device);
511 result = vtbl->GetDeviceQueue(drv_device, family, index, &queue);
512 if (result != VK_SUCCESS)
513 return result;
514 hwvulkan_dispatch_t* dispatch =
515 reinterpret_cast<hwvulkan_dispatch_t*>(queue);
516 if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC && dispatch->vtbl != &vtbl) {
517 ALOGE("invalid VkQueue dispatch magic: 0x%" PRIxPTR, dispatch->magic);
518 return VK_ERROR_INITIALIZATION_FAILED;
519 }
520 dispatch->vtbl = vtbl;
521 *out_queue = queue;
522 return VK_SUCCESS;
523}
524
Jesse Hallc7a6eb52015-08-31 12:52:03 -0700525VkResult CreateCommandBuffer(VkDevice drv_device,
526 const VkCmdBufferCreateInfo* create_info,
527 VkCmdBuffer* out_cmdbuf) {
528 const DeviceVtbl* vtbl = GetVtbl(drv_device);
529 VkCmdBuffer cmdbuf;
530 VkResult result =
531 vtbl->CreateCommandBuffer(drv_device, create_info, &cmdbuf);
532 if (result != VK_SUCCESS)
533 return result;
534 hwvulkan_dispatch_t* dispatch =
535 reinterpret_cast<hwvulkan_dispatch_t*>(cmdbuf);
536 if (dispatch->magic != HWVULKAN_DISPATCH_MAGIC) {
537 ALOGE("invalid VkCmdBuffer dispatch magic: 0x%" PRIxPTR,
538 dispatch->magic);
539 return VK_ERROR_INITIALIZATION_FAILED;
540 }
541 dispatch->vtbl = vtbl;
542 *out_cmdbuf = cmdbuf;
543 return VK_SUCCESS;
544}
545
Jesse Hall04f4f472015-08-16 19:51:04 -0700546VkResult DestroyDevice(VkDevice drv_device) {
547 const DeviceVtbl* vtbl = GetVtbl(drv_device);
548 Device* device = static_cast<Device*>(vtbl->device);
549 vtbl->DestroyDevice(drv_device);
550 DestroyDevice(device);
551 return VK_SUCCESS;
552}
553
554} // namespace vulkan