blob: 02e60b7f9a02be8711d01712f84d18a6c64f7078 [file] [log] [blame]
Chia-I Wu9d518162016-03-24 14:55:27 +08001/*
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
Chia-I Wudbb7e9c2016-03-24 15:09:38 +080017#include <stdlib.h>
18#include <string.h>
19#include <algorithm>
Chia-I Wu4901db72016-03-24 16:38:58 +080020#include <new>
Chia-I Wudbb7e9c2016-03-24 15:09:38 +080021#include <malloc.h>
Chia-I Wu9d518162016-03-24 14:55:27 +080022#include <sys/prctl.h>
23
24#include "driver.h"
Chia-I Wu136b8eb2016-03-24 15:01:52 +080025#include "loader.h"
Chia-I Wu9d518162016-03-24 14:55:27 +080026
Chia-I Wudbb7e9c2016-03-24 15:09:38 +080027// #define ENABLE_ALLOC_CALLSTACKS 1
28#if ENABLE_ALLOC_CALLSTACKS
29#include <utils/CallStack.h>
30#define ALOGD_CALLSTACK(...) \
31 do { \
32 ALOGD(__VA_ARGS__); \
33 android::CallStack callstack; \
34 callstack.update(); \
35 callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
36 } while (false)
37#else
38#define ALOGD_CALLSTACK(...) \
39 do { \
40 } while (false)
41#endif
42
Chia-I Wu9d518162016-03-24 14:55:27 +080043namespace vulkan {
44namespace driver {
45
Chia-I Wu136b8eb2016-03-24 15:01:52 +080046namespace {
47
Chia-I Wu4901db72016-03-24 16:38:58 +080048class CreateInfoWrapper {
49 public:
50 CreateInfoWrapper(VkPhysicalDevice physical_dev,
51 const VkDeviceCreateInfo& create_info,
52 const VkAllocationCallbacks& allocator);
53 ~CreateInfoWrapper();
54
55 VkResult validate();
56
57 const std::bitset<ProcHook::EXTENSION_COUNT>& get_hook_extensions() const;
58 const std::bitset<ProcHook::EXTENSION_COUNT>& get_hal_extensions() const;
59
60 explicit operator const VkDeviceCreateInfo*() const;
61
62 private:
63 struct ExtensionFilter {
64 VkExtensionProperties* exts;
65 uint32_t ext_count;
66
67 const char** names;
68 uint32_t name_count;
69 };
70
71 VkResult sanitize_pnext();
72
73 VkResult sanitize_layers();
74 VkResult sanitize_extensions();
75
76 VkResult query_extension_count(uint32_t& count) const;
77 VkResult enumerate_extensions(uint32_t& count,
78 VkExtensionProperties* props) const;
79 VkResult init_extension_filter();
80 void filter_extension(const char* name);
81
82 const bool is_instance_;
83 const VkAllocationCallbacks& allocator_;
84
85 union {
86 hwvulkan_device_t* hw_dev_;
87 VkPhysicalDevice physical_dev_;
88 };
89
90 union {
91 VkInstanceCreateInfo instance_info_;
92 VkDeviceCreateInfo dev_info_;
93 };
94
95 ExtensionFilter extension_filter_;
96
97 std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions_;
98 std::bitset<ProcHook::EXTENSION_COUNT> hal_extensions_;
99};
100
101CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
102 const VkDeviceCreateInfo& create_info,
103 const VkAllocationCallbacks& allocator)
104 : is_instance_(false),
105 allocator_(allocator),
106 physical_dev_(physical_dev),
107 dev_info_(create_info),
108 extension_filter_() {
109 hook_extensions_.set(ProcHook::EXTENSION_CORE);
110 hal_extensions_.set(ProcHook::EXTENSION_CORE);
111}
112
113CreateInfoWrapper::~CreateInfoWrapper() {
114 allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
115 allocator_.pfnFree(allocator_.pUserData, extension_filter_.names);
116}
117
118VkResult CreateInfoWrapper::validate() {
119 VkResult result = sanitize_pnext();
120 if (result == VK_SUCCESS)
121 result = sanitize_layers();
122 if (result == VK_SUCCESS)
123 result = sanitize_extensions();
124
125 return result;
126}
127
128const std::bitset<ProcHook::EXTENSION_COUNT>&
129CreateInfoWrapper::get_hook_extensions() const {
130 return hook_extensions_;
131}
132
133const std::bitset<ProcHook::EXTENSION_COUNT>&
134CreateInfoWrapper::get_hal_extensions() const {
135 return hal_extensions_;
136}
137
138CreateInfoWrapper::operator const VkDeviceCreateInfo*() const {
139 return &dev_info_;
140}
141
142VkResult CreateInfoWrapper::sanitize_pnext() {
143 const struct StructHeader {
144 VkStructureType type;
145 const void* next;
146 } * header;
147
148 if (is_instance_) {
149 header = reinterpret_cast<const StructHeader*>(instance_info_.pNext);
150
151 // skip leading VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFOs
152 while (header &&
153 header->type == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO)
154 header = reinterpret_cast<const StructHeader*>(header->next);
155
156 instance_info_.pNext = header;
157 } else {
158 header = reinterpret_cast<const StructHeader*>(dev_info_.pNext);
159
160 // skip leading VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFOs
161 while (header &&
162 header->type == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO)
163 header = reinterpret_cast<const StructHeader*>(header->next);
164
165 dev_info_.pNext = header;
166 }
167
168 return VK_SUCCESS;
169}
170
171VkResult CreateInfoWrapper::sanitize_layers() {
172 auto& layer_names = (is_instance_) ? instance_info_.ppEnabledLayerNames
173 : dev_info_.ppEnabledLayerNames;
174 auto& layer_count = (is_instance_) ? instance_info_.enabledLayerCount
175 : dev_info_.enabledLayerCount;
176
177 // remove all layers
178 layer_names = nullptr;
179 layer_count = 0;
180
181 return VK_SUCCESS;
182}
183
184VkResult CreateInfoWrapper::sanitize_extensions() {
185 auto& ext_names = (is_instance_) ? instance_info_.ppEnabledExtensionNames
186 : dev_info_.ppEnabledExtensionNames;
187 auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
188 : dev_info_.enabledExtensionCount;
189 if (!ext_count)
190 return VK_SUCCESS;
191
192 VkResult result = init_extension_filter();
193 if (result != VK_SUCCESS)
194 return result;
195
196 for (uint32_t i = 0; i < ext_count; i++)
197 filter_extension(ext_names[i]);
198
199 ext_names = extension_filter_.names;
200 ext_count = extension_filter_.name_count;
201
202 return VK_SUCCESS;
203}
204
205VkResult CreateInfoWrapper::query_extension_count(uint32_t& count) const {
206 if (is_instance_) {
207 return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
208 nullptr);
209 } else {
210 const auto& driver = GetData(physical_dev_).driver;
211 return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
212 &count, nullptr);
213 }
214}
215
216VkResult CreateInfoWrapper::enumerate_extensions(
217 uint32_t& count,
218 VkExtensionProperties* props) const {
219 if (is_instance_) {
220 return hw_dev_->EnumerateInstanceExtensionProperties(nullptr, &count,
221 props);
222 } else {
223 const auto& driver = GetData(physical_dev_).driver;
224 return driver.EnumerateDeviceExtensionProperties(physical_dev_, nullptr,
225 &count, props);
226 }
227}
228
229VkResult CreateInfoWrapper::init_extension_filter() {
230 // query extension count
231 uint32_t count;
232 VkResult result = query_extension_count(count);
233 if (result != VK_SUCCESS || count == 0)
234 return result;
235
236 auto& filter = extension_filter_;
237 filter.exts =
238 reinterpret_cast<VkExtensionProperties*>(allocator_.pfnAllocation(
239 allocator_.pUserData, sizeof(VkExtensionProperties) * count,
240 alignof(VkExtensionProperties),
241 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
242 if (!filter.exts)
243 return VK_ERROR_OUT_OF_HOST_MEMORY;
244
245 // enumerate extensions
246 result = enumerate_extensions(count, filter.exts);
247 if (result != VK_SUCCESS && result != VK_INCOMPLETE)
248 return result;
249
250 if (!count)
251 return VK_SUCCESS;
252
253 filter.ext_count = count;
254
255 // allocate name array
256 uint32_t enabled_ext_count = (is_instance_)
257 ? instance_info_.enabledExtensionCount
258 : dev_info_.enabledExtensionCount;
259 count = std::min(filter.ext_count, enabled_ext_count);
260 filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
261 allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
262 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
263 if (!filter.names)
264 return VK_ERROR_OUT_OF_HOST_MEMORY;
265
266 return VK_SUCCESS;
267}
268
269void CreateInfoWrapper::filter_extension(const char* name) {
270 auto& filter = extension_filter_;
271
272 ProcHook::Extension ext_bit = GetProcHookExtension(name);
273 if (is_instance_) {
274 switch (ext_bit) {
275 case ProcHook::KHR_android_surface:
276 case ProcHook::KHR_surface:
277 hook_extensions_.set(ext_bit);
278 // return now as these extensions do not require HAL support
279 return;
280 case ProcHook::EXT_debug_report:
281 // both we and HAL can take part in
282 hook_extensions_.set(ext_bit);
283 break;
284 case ProcHook::EXTENSION_UNKNOWN:
285 // HAL's extensions
286 break;
287 default:
288 ALOGW("Ignored invalid instance extension %s", name);
289 return;
290 }
291 } else {
292 switch (ext_bit) {
293 case ProcHook::KHR_swapchain:
294 // map VK_KHR_swapchain to VK_ANDROID_native_buffer
295 name = VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME;
296 ext_bit = ProcHook::ANDROID_native_buffer;
297 break;
298 case ProcHook::EXTENSION_UNKNOWN:
299 // HAL's extensions
300 break;
301 default:
302 ALOGW("Ignored invalid device extension %s", name);
303 return;
304 }
305 }
306
307 for (uint32_t i = 0; i < filter.ext_count; i++) {
308 const VkExtensionProperties& props = filter.exts[i];
309 // ignore unknown extensions
310 if (strcmp(name, props.extensionName) != 0)
311 continue;
312
313 if (ext_bit == ProcHook::ANDROID_native_buffer)
314 hook_extensions_.set(ProcHook::KHR_swapchain);
315
316 filter.names[filter.name_count++] = name;
317 hal_extensions_.set(ext_bit);
318
319 break;
320 }
321}
322
Chia-I Wu136b8eb2016-03-24 15:01:52 +0800323hwvulkan_device_t* g_hwdevice = nullptr;
324
Chia-I Wudbb7e9c2016-03-24 15:09:38 +0800325VKAPI_ATTR void* DefaultAllocate(void*,
326 size_t size,
327 size_t alignment,
328 VkSystemAllocationScope) {
329 void* ptr = nullptr;
330 // Vulkan requires 'alignment' to be a power of two, but posix_memalign
331 // additionally requires that it be at least sizeof(void*).
332 int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
333 ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
334 ret, ptr);
335 return ret == 0 ? ptr : nullptr;
336}
337
338VKAPI_ATTR void* DefaultReallocate(void*,
339 void* ptr,
340 size_t size,
341 size_t alignment,
342 VkSystemAllocationScope) {
343 if (size == 0) {
344 free(ptr);
345 return nullptr;
346 }
347
348 // TODO(jessehall): Right now we never shrink allocations; if the new
349 // request is smaller than the existing chunk, we just continue using it.
350 // Right now the loader never reallocs, so this doesn't matter. If that
351 // changes, or if this code is copied into some other project, this should
352 // probably have a heuristic to allocate-copy-free when doing so will save
353 // "enough" space.
354 size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
355 if (size <= old_size)
356 return ptr;
357
358 void* new_ptr = nullptr;
359 if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
360 return nullptr;
361 if (ptr) {
362 memcpy(new_ptr, ptr, std::min(old_size, size));
363 free(ptr);
364 }
365 return new_ptr;
366}
367
368VKAPI_ATTR void DefaultFree(void*, void* ptr) {
369 ALOGD_CALLSTACK("Free: %p", ptr);
370 free(ptr);
371}
372
Chia-I Wu4901db72016-03-24 16:38:58 +0800373DeviceData* AllocateDeviceData(const VkAllocationCallbacks& allocator) {
374 void* data_mem = allocator.pfnAllocation(
375 allocator.pUserData, sizeof(DeviceData), alignof(DeviceData),
376 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
377 if (!data_mem)
378 return nullptr;
379
380 return new (data_mem) DeviceData(allocator);
381}
382
383void FreeDeviceData(DeviceData* data, const VkAllocationCallbacks& allocator) {
384 data->~DeviceData();
385 allocator.pfnFree(allocator.pUserData, data);
386}
387
Chia-I Wu136b8eb2016-03-24 15:01:52 +0800388} // anonymous namespace
389
Chia-I Wu9d518162016-03-24 14:55:27 +0800390bool Debuggable() {
391 return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0);
392}
393
Chia-I Wu136b8eb2016-03-24 15:01:52 +0800394bool OpenHAL() {
395 if (g_hwdevice)
396 return true;
397
398 const hwvulkan_module_t* module;
399 int result =
400 hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module));
401 if (result != 0) {
402 ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result);
403 return false;
404 }
405
406 hwvulkan_device_t* device;
407 result =
408 module->common.methods->open(&module->common, HWVULKAN_DEVICE_0,
409 reinterpret_cast<hw_device_t**>(&device));
410 if (result != 0) {
411 ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result),
412 result);
413 return false;
414 }
415
416 if (!InitLoader(device)) {
417 device->common.close(&device->common);
418 return false;
419 }
420
421 g_hwdevice = device;
422
423 return true;
424}
425
Chia-I Wudbb7e9c2016-03-24 15:09:38 +0800426const VkAllocationCallbacks& GetDefaultAllocator() {
427 static const VkAllocationCallbacks kDefaultAllocCallbacks = {
428 .pUserData = nullptr,
429 .pfnAllocation = DefaultAllocate,
430 .pfnReallocation = DefaultReallocate,
431 .pfnFree = DefaultFree,
432 };
433
434 return kDefaultAllocCallbacks;
435}
436
Chia-I Wueb7db122016-03-24 09:11:06 +0800437PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
438 const ProcHook* hook = GetProcHook(pName);
439 if (!hook)
440 return g_hwdevice->GetInstanceProcAddr(instance, pName);
441
442 if (!instance) {
443 if (hook->type == ProcHook::GLOBAL)
444 return hook->proc;
445
446 ALOGE(
447 "Invalid use of vkGetInstanceProcAddr to query %s without an "
448 "instance",
449 pName);
450
451 // Some naughty layers expect
452 //
453 // vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice");
454 //
455 // to work.
456 return (strcmp(pName, "vkCreateDevice") == 0) ? hook->proc : nullptr;
457 }
458
459 PFN_vkVoidFunction proc;
460
461 switch (hook->type) {
462 case ProcHook::INSTANCE:
463 proc = (GetData(instance).hook_extensions[hook->extension])
464 ? hook->proc
465 : hook->disabled_proc;
466 break;
467 case ProcHook::DEVICE:
468 proc = (hook->extension == ProcHook::EXTENSION_CORE)
469 ? hook->proc
470 : hook->checked_proc;
471 break;
472 default:
473 ALOGE(
474 "Invalid use of vkGetInstanceProcAddr to query %s with an "
475 "instance",
476 pName);
477 proc = nullptr;
478 break;
479 }
480
481 return proc;
482}
483
484PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) {
485 const ProcHook* hook = GetProcHook(pName);
486 if (!hook)
Chia-I Wucc5e2762016-03-24 13:01:16 +0800487 return GetData(device).driver.GetDeviceProcAddr(device, pName);
Chia-I Wueb7db122016-03-24 09:11:06 +0800488
489 if (hook->type != ProcHook::DEVICE) {
490 ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName);
491 return nullptr;
492 }
493
494 return (GetData(device).hook_extensions[hook->extension])
495 ? hook->proc
496 : hook->disabled_proc;
497}
498
Chia-I Wu4901db72016-03-24 16:38:58 +0800499VkResult CreateDevice(VkPhysicalDevice physicalDevice,
500 const VkDeviceCreateInfo* pCreateInfo,
501 const VkAllocationCallbacks* pAllocator,
502 VkDevice* pDevice) {
503 const InstanceData& instance_data = GetData(physicalDevice);
504 const VkAllocationCallbacks& data_allocator =
505 (pAllocator) ? *pAllocator : instance_data.allocator;
506
507 CreateInfoWrapper wrapper(physicalDevice, *pCreateInfo, data_allocator);
508 VkResult result = wrapper.validate();
509 if (result != VK_SUCCESS)
510 return result;
511
512 DeviceData* data = AllocateDeviceData(data_allocator);
513 if (!data)
514 return VK_ERROR_OUT_OF_HOST_MEMORY;
515
516 data->hook_extensions |= wrapper.get_hook_extensions();
517 data->hal_extensions |= wrapper.get_hal_extensions();
518
519 // call into the driver
520 VkDevice dev;
521 result = instance_data.driver.CreateDevice(
522 physicalDevice, static_cast<const VkDeviceCreateInfo*>(wrapper),
523 pAllocator, &dev);
524 if (result != VK_SUCCESS) {
525 FreeDeviceData(data, data_allocator);
526 return result;
527 }
528
529 // initialize DeviceDriverTable
530 if (!SetData(dev, *data) ||
531 !InitDriverTable(dev, instance_data.get_device_proc_addr)) {
532 data->driver.DestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(
533 instance_data.get_device_proc_addr(dev, "vkDestroyDevice"));
534 if (data->driver.DestroyDevice)
535 data->driver.DestroyDevice(dev, pAllocator);
536
537 FreeDeviceData(data, data_allocator);
538
539 return VK_ERROR_INCOMPATIBLE_DRIVER;
540 }
541
542 *pDevice = dev;
543
544 return VK_SUCCESS;
545}
546
547void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator) {
548 DeviceData& data = GetData(device);
549 data.driver.DestroyDevice(device, pAllocator);
550
551 VkAllocationCallbacks local_allocator;
552 if (!pAllocator) {
553 local_allocator = data.allocator;
554 pAllocator = &local_allocator;
555 }
556
557 FreeDeviceData(&data, *pAllocator);
558}
559
Chia-I Wuba0be412016-03-24 16:24:40 +0800560void GetDeviceQueue(VkDevice device,
561 uint32_t queueFamilyIndex,
562 uint32_t queueIndex,
563 VkQueue* pQueue) {
564 const auto& data = GetData(device);
565
566 data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue);
567 SetData(*pQueue, data);
568}
569
Chia-I Wu6a58a8a2016-03-24 16:29:51 +0800570VKAPI_ATTR VkResult
571AllocateCommandBuffers(VkDevice device,
572 const VkCommandBufferAllocateInfo* pAllocateInfo,
573 VkCommandBuffer* pCommandBuffers) {
574 const auto& data = GetData(device);
575
576 VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo,
577 pCommandBuffers);
578 if (result == VK_SUCCESS) {
579 for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++)
580 SetData(pCommandBuffers[i], data);
581 }
582
583 return result;
584}
585
Chia-I Wu9d518162016-03-24 14:55:27 +0800586} // namespace driver
587} // namespace vulkan