blob: f2fbf3114c3a4ec7d15e05b6a844cf3c1a12f46a [file] [log] [blame]
Jesse Hall80523e22016-01-06 16:47:54 -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
Jesse Hall80523e22016-01-06 16:47:54 -080017#include "loader.h"
18#include <alloca.h>
19#include <dirent.h>
20#include <dlfcn.h>
21#include <mutex>
22#include <sys/prctl.h>
23#include <string>
24#include <string.h>
25#include <vector>
26#include <log/log.h>
27#include <vulkan/vulkan_loader_data.h>
28
29using namespace vulkan;
30
Jesse Hallaa410942016-01-17 13:07:10 -080031// TODO(jessehall): This file currently builds up global data structures as it
32// loads, and never cleans them up. This means we're doing heap allocations
33// without going through an app-provided allocator, but worse, we'll leak those
34// allocations if the loader is unloaded.
35//
36// We should allocate "enough" BSS space, and suballocate from there. Will
37// probably want to intern strings, etc., and will need some custom/manual data
38// structures.
39
40// TODO(jessehall): Currently we have separate lists for instance and device
41// layers. Most layers are both; we should use one entry for each layer name,
42// with a mask saying what kind(s) it is.
43
Jesse Hall80523e22016-01-06 16:47:54 -080044namespace vulkan {
45struct Layer {
46 VkLayerProperties properties;
47 size_t library_idx;
48 std::vector<VkExtensionProperties> extensions;
49};
50} // namespace vulkan
51
52namespace {
53
54std::mutex g_library_mutex;
55struct LayerLibrary {
56 std::string path;
57 void* dlhandle;
58 size_t refcount;
59};
60std::vector<LayerLibrary> g_layer_libraries;
Jesse Hallaa410942016-01-17 13:07:10 -080061std::vector<Layer> g_instance_layers;
62std::vector<Layer> g_device_layers;
Jesse Hall80523e22016-01-06 16:47:54 -080063
64void AddLayerLibrary(const std::string& path) {
65 ALOGV("examining layer library '%s'", path.c_str());
66
67 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
68 if (!dlhandle) {
69 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
70 return;
71 }
72
Jesse Hallaa410942016-01-17 13:07:10 -080073 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
Jesse Hall80523e22016-01-06 16:47:54 -080074 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
75 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -080076 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
Jesse Hall80523e22016-01-06 16:47:54 -080077 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
78 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -080079 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
80 reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
81 dlsym(dlhandle, "vkEnumerateDeviceLayerProperties"));
82 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
83 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
84 dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties"));
85 if (!((enumerate_instance_layers && enumerate_instance_extensions) ||
86 (enumerate_device_layers && enumerate_device_extensions))) {
87 ALOGV(
88 "layer library '%s' has neither instance nor device enumeraion "
89 "functions",
90 path.c_str());
Jesse Hall80523e22016-01-06 16:47:54 -080091 dlclose(dlhandle);
92 return;
93 }
94
Jesse Hallaa410942016-01-17 13:07:10 -080095 VkResult result;
96 uint32_t num_instance_layers = 0;
97 uint32_t num_device_layers = 0;
98 if (enumerate_instance_layers) {
99 result = enumerate_instance_layers(&num_instance_layers, nullptr);
100 if (result != VK_SUCCESS) {
101 ALOGW(
102 "vkEnumerateInstanceLayerProperties failed for library '%s': "
103 "%d",
104 path.c_str(), result);
105 dlclose(dlhandle);
106 return;
107 }
Jesse Hall80523e22016-01-06 16:47:54 -0800108 }
Jesse Hallaa410942016-01-17 13:07:10 -0800109 if (enumerate_device_layers) {
110 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
111 nullptr);
112 if (result != VK_SUCCESS) {
113 ALOGW(
114 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
115 path.c_str(), result);
116 dlclose(dlhandle);
117 return;
118 }
119 }
120 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
121 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
122 if (num_instance_layers > 0) {
123 result = enumerate_instance_layers(&num_instance_layers, properties);
124 if (result != VK_SUCCESS) {
125 ALOGW(
126 "vkEnumerateInstanceLayerProperties failed for library '%s': "
127 "%d",
128 path.c_str(), result);
129 dlclose(dlhandle);
130 return;
131 }
132 }
133 if (num_device_layers > 0) {
134 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
135 properties + num_instance_layers);
136 if (result != VK_SUCCESS) {
137 ALOGW(
138 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
139 path.c_str(), result);
140 dlclose(dlhandle);
141 return;
142 }
Jesse Hall80523e22016-01-06 16:47:54 -0800143 }
144
145 size_t library_idx = g_layer_libraries.size();
Jesse Hallaa410942016-01-17 13:07:10 -0800146 size_t prev_num_instance_layers = g_instance_layers.size();
147 size_t prev_num_device_layers = g_device_layers.size();
148 g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
149 g_device_layers.reserve(prev_num_device_layers + num_device_layers);
150 for (size_t i = 0; i < num_instance_layers; i++) {
151 const VkLayerProperties& props = properties[i];
152
Jesse Hall80523e22016-01-06 16:47:54 -0800153 Layer layer;
Jesse Hallaa410942016-01-17 13:07:10 -0800154 layer.properties = props;
Jesse Hall80523e22016-01-06 16:47:54 -0800155 layer.library_idx = library_idx;
156
Jesse Hallaa410942016-01-17 13:07:10 -0800157 if (enumerate_instance_extensions) {
158 uint32_t count = 0;
159 result =
160 enumerate_instance_extensions(props.layerName, &count, nullptr);
161 if (result != VK_SUCCESS) {
162 ALOGW(
163 "vkEnumerateInstanceExtensionProperties(%s) failed for "
164 "library "
165 "'%s': %d",
166 props.layerName, path.c_str(), result);
167 g_instance_layers.resize(prev_num_instance_layers);
168 dlclose(dlhandle);
169 return;
170 }
171 layer.extensions.resize(count);
172 result = enumerate_instance_extensions(props.layerName, &count,
173 layer.extensions.data());
174 if (result != VK_SUCCESS) {
175 ALOGW(
176 "vkEnumerateInstanceExtensionProperties(%s) failed for "
177 "library "
178 "'%s': %d",
179 props.layerName, path.c_str(), result);
180 g_instance_layers.resize(prev_num_instance_layers);
181 dlclose(dlhandle);
182 return;
183 }
Jesse Hall80523e22016-01-06 16:47:54 -0800184 }
185
Jesse Hallaa410942016-01-17 13:07:10 -0800186 g_instance_layers.push_back(layer);
187 ALOGV("added instance layer '%s'", props.layerName);
188 }
189 for (size_t i = 0; i < num_device_layers; i++) {
190 const VkLayerProperties& props = properties[num_instance_layers + i];
191
192 Layer layer;
193 layer.properties = props;
194 layer.library_idx = library_idx;
195
196 if (enumerate_device_extensions) {
197 uint32_t count;
198 result = enumerate_device_extensions(
199 VK_NULL_HANDLE, props.layerName, &count, nullptr);
200 if (result != VK_SUCCESS) {
201 ALOGW(
202 "vkEnumerateDeviceExtensionProperties(%s) failed for "
203 "library "
204 "'%s': %d",
205 props.layerName, path.c_str(), result);
206 g_instance_layers.resize(prev_num_instance_layers);
207 g_device_layers.resize(prev_num_device_layers);
208 dlclose(dlhandle);
209 return;
210 }
211 layer.extensions.resize(count);
212 result =
213 enumerate_device_extensions(VK_NULL_HANDLE, props.layerName,
214 &count, layer.extensions.data());
215 if (result != VK_SUCCESS) {
216 ALOGW(
217 "vkEnumerateDeviceExtensionProperties(%s) failed for "
218 "library "
219 "'%s': %d",
220 props.layerName, path.c_str(), result);
221 g_instance_layers.resize(prev_num_instance_layers);
222 g_device_layers.resize(prev_num_device_layers);
223 dlclose(dlhandle);
224 return;
225 }
226 }
227
228 g_device_layers.push_back(layer);
229 ALOGV("added device layer '%s'", props.layerName);
Jesse Hall80523e22016-01-06 16:47:54 -0800230 }
231
232 dlclose(dlhandle);
233
234 g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
235}
236
237void DiscoverLayersInDirectory(const std::string& dir_path) {
238 ALOGV("looking for layers in '%s'", dir_path.c_str());
239
240 DIR* directory = opendir(dir_path.c_str());
241 if (!directory) {
242 int err = errno;
243 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
244 dir_path.c_str(), strerror(err), err);
245 return;
246 }
247
248 std::string path;
249 path.reserve(dir_path.size() + 20);
250 path.append(dir_path);
251 path.append("/");
252
253 struct dirent* entry;
254 while ((entry = readdir(directory))) {
255 size_t libname_len = strlen(entry->d_name);
Jesse Halla7ac76d2016-01-08 22:29:42 -0800256 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
Jesse Hall80523e22016-01-06 16:47:54 -0800257 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
258 continue;
259 path.append(entry->d_name);
260 AddLayerLibrary(path);
261 path.resize(dir_path.size() + 1);
262 }
263
264 closedir(directory);
265}
266
267void* GetLayerGetProcAddr(const Layer& layer,
268 const char* gpa_name,
269 size_t gpa_name_len) {
270 const LayerLibrary& library = g_layer_libraries[layer.library_idx];
271 void* gpa;
Jesse Hall30ac78b2016-01-11 21:29:40 -0800272 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
Jesse Hall80523e22016-01-06 16:47:54 -0800273 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
274 strcpy(name, layer.properties.layerName);
275 strcpy(name + layer_name_len, gpa_name);
276 if (!(gpa = dlsym(library.dlhandle, name))) {
277 strcpy(name, "vk");
278 strcpy(name + 2, gpa_name);
279 gpa = dlsym(library.dlhandle, name);
280 }
281 return gpa;
282}
283
Jesse Hallaa410942016-01-17 13:07:10 -0800284uint32_t EnumerateLayers(const std::vector<Layer>& layers,
285 uint32_t count,
286 VkLayerProperties* properties) {
287 uint32_t n = std::min(count, static_cast<uint32_t>(layers.size()));
Jesse Hall80523e22016-01-06 16:47:54 -0800288 for (uint32_t i = 0; i < n; i++) {
Jesse Hallaa410942016-01-17 13:07:10 -0800289 properties[i] = layers[i].properties;
Jesse Hall80523e22016-01-06 16:47:54 -0800290 }
Jesse Hallaa410942016-01-17 13:07:10 -0800291 return static_cast<uint32_t>(layers.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800292}
293
Jesse Hallaa410942016-01-17 13:07:10 -0800294void GetLayerExtensions(const std::vector<Layer>& layers,
295 const char* name,
Jesse Hall80523e22016-01-06 16:47:54 -0800296 const VkExtensionProperties** properties,
297 uint32_t* count) {
Jesse Hallaa410942016-01-17 13:07:10 -0800298 auto layer =
299 std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) {
300 return strcmp(entry.properties.layerName, name) == 0;
301 });
302 if (layer == layers.cend()) {
303 *properties = nullptr;
304 *count = 0;
305 } else {
306 *properties = layer->extensions.data();
307 *count = static_cast<uint32_t>(layer->extensions.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800308 }
309}
310
Jesse Hallaa410942016-01-17 13:07:10 -0800311LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) {
312 for (uint32_t id = 0; id < layers.size(); id++) {
313 if (strcmp(name, layers[id].properties.layerName) != 0) {
314 LayerLibrary& library = g_layer_libraries[layers[id].library_idx];
Jesse Hall80523e22016-01-06 16:47:54 -0800315 std::lock_guard<std::mutex> lock(g_library_mutex);
316 if (library.refcount++ == 0) {
317 library.dlhandle =
318 dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL);
319 if (!library.dlhandle) {
320 ALOGE("failed to load layer library '%s': %s",
321 library.path.c_str(), dlerror());
322 library.refcount = 0;
323 return LayerRef(nullptr);
324 }
325 }
Jesse Hallaa410942016-01-17 13:07:10 -0800326 return LayerRef(&layers[id]);
Jesse Hall80523e22016-01-06 16:47:54 -0800327 }
328 }
329 return LayerRef(nullptr);
330}
331
Jesse Hallaa410942016-01-17 13:07:10 -0800332} // anonymous namespace
333
334namespace vulkan {
335
336void DiscoverLayers() {
337 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
338 DiscoverLayersInDirectory("/data/local/debug/vulkan");
339 if (!LoaderData::GetInstance().layer_path.empty())
340 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
341}
342
343uint32_t EnumerateInstanceLayers(uint32_t count,
344 VkLayerProperties* properties) {
345 return EnumerateLayers(g_instance_layers, count, properties);
346}
347
348uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) {
349 return EnumerateLayers(g_device_layers, count, properties);
350}
351
352void GetInstanceLayerExtensions(const char* name,
353 const VkExtensionProperties** properties,
354 uint32_t* count) {
355 GetLayerExtensions(g_instance_layers, name, properties, count);
356}
357
358void GetDeviceLayerExtensions(const char* name,
359 const VkExtensionProperties** properties,
360 uint32_t* count) {
361 GetLayerExtensions(g_device_layers, name, properties, count);
362}
363
364LayerRef GetInstanceLayerRef(const char* name) {
365 return GetLayerRef(g_instance_layers, name);
366}
367
368LayerRef GetDeviceLayerRef(const char* name) {
369 return GetLayerRef(g_device_layers, name);
370}
371
Jesse Hall80523e22016-01-06 16:47:54 -0800372LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
373
374LayerRef::~LayerRef() {
375 if (layer_) {
376 LayerLibrary& library = g_layer_libraries[layer_->library_idx];
377 std::lock_guard<std::mutex> lock(g_library_mutex);
378 if (--library.refcount == 0) {
379 dlclose(library.dlhandle);
380 library.dlhandle = nullptr;
381 }
382 }
383}
384
385LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {}
386
387PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
388 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
389 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
390 : nullptr;
391}
392
393PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
394 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
395 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
396 : nullptr;
397}
398
Jesse Hall6bd5dfa2016-01-16 17:13:30 -0800399InstanceExtension InstanceExtensionFromName(const char* name) {
400 if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
401 return kKHR_surface;
402 if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0)
403 return kKHR_android_surface;
404 if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
405 return kEXT_debug_report;
406 return kInstanceExtensionCount;
407}
408
Jesse Hall80523e22016-01-06 16:47:54 -0800409} // namespace vulkan