driver.cpp revision 6a58a8a7813450038cb15575e3333b83f268c972
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 <malloc.h> 21#include <sys/prctl.h> 22 23#include "driver.h" 24#include "loader.h" 25 26// #define ENABLE_ALLOC_CALLSTACKS 1 27#if ENABLE_ALLOC_CALLSTACKS 28#include <utils/CallStack.h> 29#define ALOGD_CALLSTACK(...) \ 30 do { \ 31 ALOGD(__VA_ARGS__); \ 32 android::CallStack callstack; \ 33 callstack.update(); \ 34 callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \ 35 } while (false) 36#else 37#define ALOGD_CALLSTACK(...) \ 38 do { \ 39 } while (false) 40#endif 41 42namespace vulkan { 43namespace driver { 44 45namespace { 46 47hwvulkan_device_t* g_hwdevice = nullptr; 48 49VKAPI_ATTR void* DefaultAllocate(void*, 50 size_t size, 51 size_t alignment, 52 VkSystemAllocationScope) { 53 void* ptr = nullptr; 54 // Vulkan requires 'alignment' to be a power of two, but posix_memalign 55 // additionally requires that it be at least sizeof(void*). 56 int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size); 57 ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment, 58 ret, ptr); 59 return ret == 0 ? ptr : nullptr; 60} 61 62VKAPI_ATTR void* DefaultReallocate(void*, 63 void* ptr, 64 size_t size, 65 size_t alignment, 66 VkSystemAllocationScope) { 67 if (size == 0) { 68 free(ptr); 69 return nullptr; 70 } 71 72 // TODO(jessehall): Right now we never shrink allocations; if the new 73 // request is smaller than the existing chunk, we just continue using it. 74 // Right now the loader never reallocs, so this doesn't matter. If that 75 // changes, or if this code is copied into some other project, this should 76 // probably have a heuristic to allocate-copy-free when doing so will save 77 // "enough" space. 78 size_t old_size = ptr ? malloc_usable_size(ptr) : 0; 79 if (size <= old_size) 80 return ptr; 81 82 void* new_ptr = nullptr; 83 if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0) 84 return nullptr; 85 if (ptr) { 86 memcpy(new_ptr, ptr, std::min(old_size, size)); 87 free(ptr); 88 } 89 return new_ptr; 90} 91 92VKAPI_ATTR void DefaultFree(void*, void* ptr) { 93 ALOGD_CALLSTACK("Free: %p", ptr); 94 free(ptr); 95} 96 97} // anonymous namespace 98 99bool Debuggable() { 100 return (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) >= 0); 101} 102 103bool OpenHAL() { 104 if (g_hwdevice) 105 return true; 106 107 const hwvulkan_module_t* module; 108 int result = 109 hw_get_module("vulkan", reinterpret_cast<const hw_module_t**>(&module)); 110 if (result != 0) { 111 ALOGE("failed to load vulkan hal: %s (%d)", strerror(-result), result); 112 return false; 113 } 114 115 hwvulkan_device_t* device; 116 result = 117 module->common.methods->open(&module->common, HWVULKAN_DEVICE_0, 118 reinterpret_cast<hw_device_t**>(&device)); 119 if (result != 0) { 120 ALOGE("failed to open vulkan driver: %s (%d)", strerror(-result), 121 result); 122 return false; 123 } 124 125 if (!InitLoader(device)) { 126 device->common.close(&device->common); 127 return false; 128 } 129 130 g_hwdevice = device; 131 132 return true; 133} 134 135const VkAllocationCallbacks& GetDefaultAllocator() { 136 static const VkAllocationCallbacks kDefaultAllocCallbacks = { 137 .pUserData = nullptr, 138 .pfnAllocation = DefaultAllocate, 139 .pfnReallocation = DefaultReallocate, 140 .pfnFree = DefaultFree, 141 }; 142 143 return kDefaultAllocCallbacks; 144} 145 146PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) { 147 const ProcHook* hook = GetProcHook(pName); 148 if (!hook) 149 return g_hwdevice->GetInstanceProcAddr(instance, pName); 150 151 if (!instance) { 152 if (hook->type == ProcHook::GLOBAL) 153 return hook->proc; 154 155 ALOGE( 156 "Invalid use of vkGetInstanceProcAddr to query %s without an " 157 "instance", 158 pName); 159 160 // Some naughty layers expect 161 // 162 // vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateDevice"); 163 // 164 // to work. 165 return (strcmp(pName, "vkCreateDevice") == 0) ? hook->proc : nullptr; 166 } 167 168 PFN_vkVoidFunction proc; 169 170 switch (hook->type) { 171 case ProcHook::INSTANCE: 172 proc = (GetData(instance).hook_extensions[hook->extension]) 173 ? hook->proc 174 : hook->disabled_proc; 175 break; 176 case ProcHook::DEVICE: 177 proc = (hook->extension == ProcHook::EXTENSION_CORE) 178 ? hook->proc 179 : hook->checked_proc; 180 break; 181 default: 182 ALOGE( 183 "Invalid use of vkGetInstanceProcAddr to query %s with an " 184 "instance", 185 pName); 186 proc = nullptr; 187 break; 188 } 189 190 return proc; 191} 192 193PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pName) { 194 const ProcHook* hook = GetProcHook(pName); 195 if (!hook) 196 return GetData(device).driver.GetDeviceProcAddr(device, pName); 197 198 if (hook->type != ProcHook::DEVICE) { 199 ALOGE("Invalid use of vkGetDeviceProcAddr to query %s", pName); 200 return nullptr; 201 } 202 203 return (GetData(device).hook_extensions[hook->extension]) 204 ? hook->proc 205 : hook->disabled_proc; 206} 207 208void GetDeviceQueue(VkDevice device, 209 uint32_t queueFamilyIndex, 210 uint32_t queueIndex, 211 VkQueue* pQueue) { 212 const auto& data = GetData(device); 213 214 data.driver.GetDeviceQueue(device, queueFamilyIndex, queueIndex, pQueue); 215 SetData(*pQueue, data); 216} 217 218VKAPI_ATTR VkResult 219AllocateCommandBuffers(VkDevice device, 220 const VkCommandBufferAllocateInfo* pAllocateInfo, 221 VkCommandBuffer* pCommandBuffers) { 222 const auto& data = GetData(device); 223 224 VkResult result = data.driver.AllocateCommandBuffers(device, pAllocateInfo, 225 pCommandBuffers); 226 if (result == VK_SUCCESS) { 227 for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) 228 SetData(pCommandBuffers[i], data); 229 } 230 231 return result; 232} 233 234} // namespace driver 235} // namespace vulkan 236