driver.cpp revision cc5e2765a9d56b03b69d0c3f25b94721f82d034e
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
208}  // namespace driver
209}  // namespace vulkan
210