layers_extensions.cpp revision 6bd5dfa9b94d1f1b2d9b6bae52979502c44c2847
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// #define LOG_NDEBUG 0
18
19#include "loader.h"
20#include <alloca.h>
21#include <dirent.h>
22#include <dlfcn.h>
23#include <mutex>
24#include <sys/prctl.h>
25#include <string>
26#include <string.h>
27#include <vector>
28#include <log/log.h>
29#include <vulkan/vulkan_loader_data.h>
30
31using namespace vulkan;
32
33namespace vulkan {
34struct Layer {
35    VkLayerProperties properties;
36    size_t library_idx;
37    std::vector<VkExtensionProperties> extensions;
38};
39}  // namespace vulkan
40
41namespace {
42
43std::mutex g_library_mutex;
44struct LayerLibrary {
45    std::string path;
46    void* dlhandle;
47    size_t refcount;
48};
49std::vector<LayerLibrary> g_layer_libraries;
50std::vector<Layer> g_layers;
51
52void AddLayerLibrary(const std::string& path) {
53    ALOGV("examining layer library '%s'", path.c_str());
54
55    void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
56    if (!dlhandle) {
57        ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
58        return;
59    }
60
61    PFN_vkEnumerateInstanceLayerProperties enumerate_layer_properties =
62        reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
63            dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
64    if (!enumerate_layer_properties) {
65        ALOGW(
66            "failed to find vkEnumerateInstanceLayerProperties in library "
67            "'%s': %s",
68            path.c_str(), dlerror());
69        dlclose(dlhandle);
70        return;
71    }
72    PFN_vkEnumerateInstanceExtensionProperties enumerate_extension_properties =
73        reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
74            dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
75    if (!enumerate_extension_properties) {
76        ALOGW(
77            "failed to find vkEnumerateInstanceExtensionProperties in library "
78            "'%s': %s",
79            path.c_str(), dlerror());
80        dlclose(dlhandle);
81        return;
82    }
83
84    uint32_t layer_count;
85    VkResult result = enumerate_layer_properties(&layer_count, nullptr);
86    if (result != VK_SUCCESS) {
87        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
88              path.c_str(), result);
89        dlclose(dlhandle);
90        return;
91    }
92    VkLayerProperties* properties = static_cast<VkLayerProperties*>(
93        alloca(layer_count * sizeof(VkLayerProperties)));
94    result = enumerate_layer_properties(&layer_count, properties);
95    if (result != VK_SUCCESS) {
96        ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
97              path.c_str(), result);
98        dlclose(dlhandle);
99        return;
100    }
101
102    size_t library_idx = g_layer_libraries.size();
103    g_layers.reserve(g_layers.size() + layer_count);
104    for (size_t i = 0; i < layer_count; i++) {
105        Layer layer;
106        layer.properties = properties[i];
107        layer.library_idx = library_idx;
108
109        uint32_t count;
110        result = enumerate_extension_properties(properties[i].layerName, &count,
111                                                nullptr);
112        if (result != VK_SUCCESS) {
113            ALOGW(
114                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
115                "'%s': %d",
116                properties[i].layerName, path.c_str(), result);
117            g_layers.resize(g_layers.size() - (i + 1));
118            dlclose(dlhandle);
119            return;
120        }
121        layer.extensions.resize(count);
122        result = enumerate_extension_properties(properties[i].layerName, &count,
123                                                layer.extensions.data());
124        if (result != VK_SUCCESS) {
125            ALOGW(
126                "vkEnumerateInstanceExtensionProperties(%s) failed for library "
127                "'%s': %d",
128                properties[i].layerName, path.c_str(), result);
129            g_layers.resize(g_layers.size() - (i + 1));
130            dlclose(dlhandle);
131            return;
132        }
133
134        g_layers.push_back(layer);
135        ALOGV("found layer '%s'", properties[i].layerName);
136    }
137
138    dlclose(dlhandle);
139
140    g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
141}
142
143void DiscoverLayersInDirectory(const std::string& dir_path) {
144    ALOGV("looking for layers in '%s'", dir_path.c_str());
145
146    DIR* directory = opendir(dir_path.c_str());
147    if (!directory) {
148        int err = errno;
149        ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
150                 dir_path.c_str(), strerror(err), err);
151        return;
152    }
153
154    std::string path;
155    path.reserve(dir_path.size() + 20);
156    path.append(dir_path);
157    path.append("/");
158
159    struct dirent* entry;
160    while ((entry = readdir(directory))) {
161        size_t libname_len = strlen(entry->d_name);
162        if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
163            strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
164            continue;
165        path.append(entry->d_name);
166        AddLayerLibrary(path);
167        path.resize(dir_path.size() + 1);
168    }
169
170    closedir(directory);
171}
172
173void* GetLayerGetProcAddr(const Layer& layer,
174                          const char* gpa_name,
175                          size_t gpa_name_len) {
176    const LayerLibrary& library = g_layer_libraries[layer.library_idx];
177    void* gpa;
178    size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
179    char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
180    strcpy(name, layer.properties.layerName);
181    strcpy(name + layer_name_len, gpa_name);
182    if (!(gpa = dlsym(library.dlhandle, name))) {
183        strcpy(name, "vk");
184        strcpy(name + 2, gpa_name);
185        gpa = dlsym(library.dlhandle, name);
186    }
187    return gpa;
188}
189
190}  // anonymous namespace
191
192namespace vulkan {
193
194void DiscoverLayers() {
195    if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
196        DiscoverLayersInDirectory("/data/local/debug/vulkan");
197    if (!LoaderData::GetInstance().layer_path.empty())
198        DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
199}
200
201uint32_t EnumerateLayers(uint32_t count, VkLayerProperties* properties) {
202    uint32_t n = std::min(count, static_cast<uint32_t>(g_layers.size()));
203    for (uint32_t i = 0; i < n; i++) {
204        properties[i] = g_layers[i].properties;
205    }
206    return static_cast<uint32_t>(g_layers.size());
207}
208
209void GetLayerExtensions(const char* name,
210                        const VkExtensionProperties** properties,
211                        uint32_t* count) {
212    for (const auto& layer : g_layers) {
213        if (strcmp(name, layer.properties.layerName) != 0)
214            continue;
215        *properties = layer.extensions.data();
216        *count = static_cast<uint32_t>(layer.extensions.size());
217    }
218}
219
220LayerRef GetLayerRef(const char* name) {
221    for (uint32_t id = 0; id < g_layers.size(); id++) {
222        if (strcmp(name, g_layers[id].properties.layerName) != 0) {
223            LayerLibrary& library = g_layer_libraries[g_layers[id].library_idx];
224            std::lock_guard<std::mutex> lock(g_library_mutex);
225            if (library.refcount++ == 0) {
226                library.dlhandle =
227                    dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL);
228                if (!library.dlhandle) {
229                    ALOGE("failed to load layer library '%s': %s",
230                          library.path.c_str(), dlerror());
231                    library.refcount = 0;
232                    return LayerRef(nullptr);
233                }
234            }
235            return LayerRef(&g_layers[id]);
236        }
237    }
238    return LayerRef(nullptr);
239}
240
241LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
242
243LayerRef::~LayerRef() {
244    if (layer_) {
245        LayerLibrary& library = g_layer_libraries[layer_->library_idx];
246        std::lock_guard<std::mutex> lock(g_library_mutex);
247        if (--library.refcount == 0) {
248            dlclose(library.dlhandle);
249            library.dlhandle = nullptr;
250        }
251    }
252}
253
254LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {}
255
256PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
257    return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
258                        GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
259                  : nullptr;
260}
261
262PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
263    return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
264                        GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
265                  : nullptr;
266}
267
268InstanceExtension InstanceExtensionFromName(const char* name) {
269    if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
270        return kKHR_surface;
271    if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0)
272        return kKHR_android_surface;
273    if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
274        return kEXT_debug_report;
275    return kInstanceExtensionCount;
276}
277
278}  // namespace vulkan
279