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