blob: 3e7fbec4bb00f8984fee6394856763a8a7225d87 [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 Hallb1471272016-01-17 21:36:58 -080031// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
32// not a good long-term solution. Having a hard-coded enum of extensions is
33// bad, of course. Representing sets of extensions (requested, supported, etc.)
34// as a bitset isn't necessarily bad, if the mapping from extension to bit were
35// dynamic. Need to rethink this completely when there's a little more time.
36
Jesse Hallaa410942016-01-17 13:07:10 -080037// TODO(jessehall): This file currently builds up global data structures as it
38// loads, and never cleans them up. This means we're doing heap allocations
39// without going through an app-provided allocator, but worse, we'll leak those
40// allocations if the loader is unloaded.
41//
42// We should allocate "enough" BSS space, and suballocate from there. Will
43// probably want to intern strings, etc., and will need some custom/manual data
44// structures.
45
46// TODO(jessehall): Currently we have separate lists for instance and device
47// layers. Most layers are both; we should use one entry for each layer name,
48// with a mask saying what kind(s) it is.
49
Jesse Hall80523e22016-01-06 16:47:54 -080050namespace vulkan {
51struct Layer {
52 VkLayerProperties properties;
53 size_t library_idx;
54 std::vector<VkExtensionProperties> extensions;
55};
56} // namespace vulkan
57
58namespace {
59
60std::mutex g_library_mutex;
61struct LayerLibrary {
62 std::string path;
63 void* dlhandle;
64 size_t refcount;
65};
66std::vector<LayerLibrary> g_layer_libraries;
Jesse Hallaa410942016-01-17 13:07:10 -080067std::vector<Layer> g_instance_layers;
68std::vector<Layer> g_device_layers;
Jesse Hall80523e22016-01-06 16:47:54 -080069
70void AddLayerLibrary(const std::string& path) {
71 ALOGV("examining layer library '%s'", path.c_str());
72
73 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
74 if (!dlhandle) {
75 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
76 return;
77 }
78
Jesse Hallaa410942016-01-17 13:07:10 -080079 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
Jesse Hall80523e22016-01-06 16:47:54 -080080 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
81 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -080082 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
Jesse Hall80523e22016-01-06 16:47:54 -080083 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
84 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -080085 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
86 reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
87 dlsym(dlhandle, "vkEnumerateDeviceLayerProperties"));
88 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
89 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
90 dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties"));
91 if (!((enumerate_instance_layers && enumerate_instance_extensions) ||
92 (enumerate_device_layers && enumerate_device_extensions))) {
93 ALOGV(
94 "layer library '%s' has neither instance nor device enumeraion "
95 "functions",
96 path.c_str());
Jesse Hall80523e22016-01-06 16:47:54 -080097 dlclose(dlhandle);
98 return;
99 }
100
Jesse Hallaa410942016-01-17 13:07:10 -0800101 VkResult result;
102 uint32_t num_instance_layers = 0;
103 uint32_t num_device_layers = 0;
104 if (enumerate_instance_layers) {
105 result = enumerate_instance_layers(&num_instance_layers, nullptr);
106 if (result != VK_SUCCESS) {
107 ALOGW(
108 "vkEnumerateInstanceLayerProperties failed for library '%s': "
109 "%d",
110 path.c_str(), result);
111 dlclose(dlhandle);
112 return;
113 }
Jesse Hall80523e22016-01-06 16:47:54 -0800114 }
Jesse Hallaa410942016-01-17 13:07:10 -0800115 if (enumerate_device_layers) {
116 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
117 nullptr);
118 if (result != VK_SUCCESS) {
119 ALOGW(
120 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
121 path.c_str(), result);
122 dlclose(dlhandle);
123 return;
124 }
125 }
126 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
127 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
128 if (num_instance_layers > 0) {
129 result = enumerate_instance_layers(&num_instance_layers, properties);
130 if (result != VK_SUCCESS) {
131 ALOGW(
132 "vkEnumerateInstanceLayerProperties failed for library '%s': "
133 "%d",
134 path.c_str(), result);
135 dlclose(dlhandle);
136 return;
137 }
138 }
139 if (num_device_layers > 0) {
140 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
141 properties + num_instance_layers);
142 if (result != VK_SUCCESS) {
143 ALOGW(
144 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
145 path.c_str(), result);
146 dlclose(dlhandle);
147 return;
148 }
Jesse Hall80523e22016-01-06 16:47:54 -0800149 }
150
151 size_t library_idx = g_layer_libraries.size();
Jesse Hallaa410942016-01-17 13:07:10 -0800152 size_t prev_num_instance_layers = g_instance_layers.size();
153 size_t prev_num_device_layers = g_device_layers.size();
154 g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
155 g_device_layers.reserve(prev_num_device_layers + num_device_layers);
156 for (size_t i = 0; i < num_instance_layers; i++) {
157 const VkLayerProperties& props = properties[i];
158
Jesse Hall80523e22016-01-06 16:47:54 -0800159 Layer layer;
Jesse Hallaa410942016-01-17 13:07:10 -0800160 layer.properties = props;
Jesse Hall80523e22016-01-06 16:47:54 -0800161 layer.library_idx = library_idx;
162
Jesse Hallaa410942016-01-17 13:07:10 -0800163 if (enumerate_instance_extensions) {
164 uint32_t count = 0;
165 result =
166 enumerate_instance_extensions(props.layerName, &count, nullptr);
167 if (result != VK_SUCCESS) {
168 ALOGW(
169 "vkEnumerateInstanceExtensionProperties(%s) failed for "
170 "library "
171 "'%s': %d",
172 props.layerName, path.c_str(), result);
173 g_instance_layers.resize(prev_num_instance_layers);
174 dlclose(dlhandle);
175 return;
176 }
177 layer.extensions.resize(count);
178 result = enumerate_instance_extensions(props.layerName, &count,
179 layer.extensions.data());
180 if (result != VK_SUCCESS) {
181 ALOGW(
182 "vkEnumerateInstanceExtensionProperties(%s) failed for "
183 "library "
184 "'%s': %d",
185 props.layerName, path.c_str(), result);
186 g_instance_layers.resize(prev_num_instance_layers);
187 dlclose(dlhandle);
188 return;
189 }
Jesse Hall80523e22016-01-06 16:47:54 -0800190 }
191
Jesse Hallaa410942016-01-17 13:07:10 -0800192 g_instance_layers.push_back(layer);
Jesse Hallb1471272016-01-17 21:36:58 -0800193 ALOGV(" added instance layer '%s'", props.layerName);
Jesse Hallaa410942016-01-17 13:07:10 -0800194 }
195 for (size_t i = 0; i < num_device_layers; i++) {
196 const VkLayerProperties& props = properties[num_instance_layers + i];
197
198 Layer layer;
199 layer.properties = props;
200 layer.library_idx = library_idx;
201
202 if (enumerate_device_extensions) {
203 uint32_t count;
204 result = enumerate_device_extensions(
205 VK_NULL_HANDLE, props.layerName, &count, nullptr);
206 if (result != VK_SUCCESS) {
207 ALOGW(
208 "vkEnumerateDeviceExtensionProperties(%s) failed for "
209 "library "
210 "'%s': %d",
211 props.layerName, path.c_str(), result);
212 g_instance_layers.resize(prev_num_instance_layers);
213 g_device_layers.resize(prev_num_device_layers);
214 dlclose(dlhandle);
215 return;
216 }
217 layer.extensions.resize(count);
218 result =
219 enumerate_device_extensions(VK_NULL_HANDLE, props.layerName,
220 &count, layer.extensions.data());
221 if (result != VK_SUCCESS) {
222 ALOGW(
223 "vkEnumerateDeviceExtensionProperties(%s) failed for "
224 "library "
225 "'%s': %d",
226 props.layerName, path.c_str(), result);
227 g_instance_layers.resize(prev_num_instance_layers);
228 g_device_layers.resize(prev_num_device_layers);
229 dlclose(dlhandle);
230 return;
231 }
232 }
233
234 g_device_layers.push_back(layer);
Jesse Hallb1471272016-01-17 21:36:58 -0800235 ALOGV(" added device layer '%s'", props.layerName);
Jesse Hall80523e22016-01-06 16:47:54 -0800236 }
237
238 dlclose(dlhandle);
239
240 g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0});
241}
242
243void DiscoverLayersInDirectory(const std::string& dir_path) {
244 ALOGV("looking for layers in '%s'", dir_path.c_str());
245
246 DIR* directory = opendir(dir_path.c_str());
247 if (!directory) {
248 int err = errno;
249 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
250 dir_path.c_str(), strerror(err), err);
251 return;
252 }
253
254 std::string path;
255 path.reserve(dir_path.size() + 20);
256 path.append(dir_path);
257 path.append("/");
258
259 struct dirent* entry;
260 while ((entry = readdir(directory))) {
261 size_t libname_len = strlen(entry->d_name);
Jesse Halla7ac76d2016-01-08 22:29:42 -0800262 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
Jesse Hall80523e22016-01-06 16:47:54 -0800263 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
264 continue;
265 path.append(entry->d_name);
266 AddLayerLibrary(path);
267 path.resize(dir_path.size() + 1);
268 }
269
270 closedir(directory);
271}
272
273void* GetLayerGetProcAddr(const Layer& layer,
274 const char* gpa_name,
275 size_t gpa_name_len) {
276 const LayerLibrary& library = g_layer_libraries[layer.library_idx];
277 void* gpa;
Jesse Hall30ac78b2016-01-11 21:29:40 -0800278 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
Jesse Hall80523e22016-01-06 16:47:54 -0800279 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
280 strcpy(name, layer.properties.layerName);
281 strcpy(name + layer_name_len, gpa_name);
282 if (!(gpa = dlsym(library.dlhandle, name))) {
283 strcpy(name, "vk");
284 strcpy(name + 2, gpa_name);
285 gpa = dlsym(library.dlhandle, name);
286 }
287 return gpa;
288}
289
Jesse Hallaa410942016-01-17 13:07:10 -0800290uint32_t EnumerateLayers(const std::vector<Layer>& layers,
291 uint32_t count,
292 VkLayerProperties* properties) {
293 uint32_t n = std::min(count, static_cast<uint32_t>(layers.size()));
Jesse Hall80523e22016-01-06 16:47:54 -0800294 for (uint32_t i = 0; i < n; i++) {
Jesse Hallaa410942016-01-17 13:07:10 -0800295 properties[i] = layers[i].properties;
Jesse Hall80523e22016-01-06 16:47:54 -0800296 }
Jesse Hallaa410942016-01-17 13:07:10 -0800297 return static_cast<uint32_t>(layers.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800298}
299
Jesse Hallaa410942016-01-17 13:07:10 -0800300void GetLayerExtensions(const std::vector<Layer>& layers,
301 const char* name,
Jesse Hall80523e22016-01-06 16:47:54 -0800302 const VkExtensionProperties** properties,
303 uint32_t* count) {
Jesse Hallaa410942016-01-17 13:07:10 -0800304 auto layer =
305 std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) {
306 return strcmp(entry.properties.layerName, name) == 0;
307 });
308 if (layer == layers.cend()) {
309 *properties = nullptr;
310 *count = 0;
311 } else {
312 *properties = layer->extensions.data();
313 *count = static_cast<uint32_t>(layer->extensions.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800314 }
315}
316
Jesse Hallaa410942016-01-17 13:07:10 -0800317LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) {
318 for (uint32_t id = 0; id < layers.size(); id++) {
319 if (strcmp(name, layers[id].properties.layerName) != 0) {
320 LayerLibrary& library = g_layer_libraries[layers[id].library_idx];
Jesse Hall80523e22016-01-06 16:47:54 -0800321 std::lock_guard<std::mutex> lock(g_library_mutex);
322 if (library.refcount++ == 0) {
323 library.dlhandle =
324 dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL);
325 if (!library.dlhandle) {
326 ALOGE("failed to load layer library '%s': %s",
327 library.path.c_str(), dlerror());
328 library.refcount = 0;
329 return LayerRef(nullptr);
330 }
331 }
Jesse Hallaa410942016-01-17 13:07:10 -0800332 return LayerRef(&layers[id]);
Jesse Hall80523e22016-01-06 16:47:54 -0800333 }
334 }
335 return LayerRef(nullptr);
336}
337
Jesse Hallaa410942016-01-17 13:07:10 -0800338} // anonymous namespace
339
340namespace vulkan {
341
342void DiscoverLayers() {
343 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
344 DiscoverLayersInDirectory("/data/local/debug/vulkan");
345 if (!LoaderData::GetInstance().layer_path.empty())
346 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
347}
348
349uint32_t EnumerateInstanceLayers(uint32_t count,
350 VkLayerProperties* properties) {
351 return EnumerateLayers(g_instance_layers, count, properties);
352}
353
354uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) {
355 return EnumerateLayers(g_device_layers, count, properties);
356}
357
358void GetInstanceLayerExtensions(const char* name,
359 const VkExtensionProperties** properties,
360 uint32_t* count) {
361 GetLayerExtensions(g_instance_layers, name, properties, count);
362}
363
364void GetDeviceLayerExtensions(const char* name,
365 const VkExtensionProperties** properties,
366 uint32_t* count) {
367 GetLayerExtensions(g_device_layers, name, properties, count);
368}
369
370LayerRef GetInstanceLayerRef(const char* name) {
371 return GetLayerRef(g_instance_layers, name);
372}
373
374LayerRef GetDeviceLayerRef(const char* name) {
375 return GetLayerRef(g_device_layers, name);
376}
377
Jesse Hall80523e22016-01-06 16:47:54 -0800378LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
379
380LayerRef::~LayerRef() {
381 if (layer_) {
382 LayerLibrary& library = g_layer_libraries[layer_->library_idx];
383 std::lock_guard<std::mutex> lock(g_library_mutex);
384 if (--library.refcount == 0) {
385 dlclose(library.dlhandle);
386 library.dlhandle = nullptr;
387 }
388 }
389}
390
391LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {}
392
393PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
394 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
395 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
396 : nullptr;
397}
398
399PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
400 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
401 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
402 : nullptr;
403}
404
Jesse Hallb1471272016-01-17 21:36:58 -0800405bool LayerRef::SupportsExtension(const char* name) const {
406 return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(),
407 [=](const VkExtensionProperties& ext) {
408 return strcmp(ext.extensionName, name) == 0;
409 }) != layer_->extensions.cend();
410}
411
Jesse Hall6bd5dfa2016-01-16 17:13:30 -0800412InstanceExtension InstanceExtensionFromName(const char* name) {
413 if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0)
414 return kKHR_surface;
415 if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0)
416 return kKHR_android_surface;
417 if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
418 return kEXT_debug_report;
419 return kInstanceExtensionCount;
420}
421
Jesse Hallb1471272016-01-17 21:36:58 -0800422DeviceExtension DeviceExtensionFromName(const char* name) {
423 if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0)
424 return kKHR_swapchain;
425 if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0)
426 return kANDROID_native_buffer;
427 return kDeviceExtensionCount;
428}
429
Jesse Hall80523e22016-01-06 16:47:54 -0800430} // namespace vulkan