blob: 51a26a134b5c02c4f6fe225af17b706166fd0bc7 [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
Michael Lentined0b7cb52016-01-19 13:57:26 -060017// #define LOG_NDEBUG 0
18
Chia-I Wuc96880f2016-03-26 06:56:45 +080019#include "layers_extensions.h"
Jesse Hall80523e22016-01-06 16:47:54 -080020#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
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 {
Chia-I Wuc96880f2016-03-26 06:56:45 +080051namespace api {
52
Jesse Hall80523e22016-01-06 16:47:54 -080053struct Layer {
54 VkLayerProperties properties;
55 size_t library_idx;
56 std::vector<VkExtensionProperties> extensions;
57};
Jesse Hall80523e22016-01-06 16:47:54 -080058
59namespace {
60
Jesse Hall80523e22016-01-06 16:47:54 -080061struct LayerLibrary {
Chia-I Wu74349592016-04-18 12:08:39 +080062 LayerLibrary(const std::string& path_)
63 : path(path_), dlhandle(nullptr), refcount(0) {}
64
Chia-I Wufd0389f2016-04-18 12:11:00 +080065 bool Open();
66
Jesse Hall80523e22016-01-06 16:47:54 -080067 std::string path;
68 void* dlhandle;
69 size_t refcount;
70};
Chia-I Wu74349592016-04-18 12:08:39 +080071
Chia-I Wufd0389f2016-04-18 12:11:00 +080072bool LayerLibrary::Open() {
73 if (refcount++ == 0) {
74 dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
75 ALOGV("Opening library %s", path.c_str());
76 if (!dlhandle) {
77 ALOGE("failed to load layer library '%s': %s", path.c_str(),
78 dlerror());
79 refcount = 0;
80 return false;
81 }
82 }
83 ALOGV("Refcount on activate is %zu", refcount);
84 return true;
85}
86
Chia-I Wu74349592016-04-18 12:08:39 +080087std::mutex g_library_mutex;
Jesse Hall80523e22016-01-06 16:47:54 -080088std::vector<LayerLibrary> g_layer_libraries;
Jesse Hallaa410942016-01-17 13:07:10 -080089std::vector<Layer> g_instance_layers;
90std::vector<Layer> g_device_layers;
Jesse Hall80523e22016-01-06 16:47:54 -080091
92void AddLayerLibrary(const std::string& path) {
93 ALOGV("examining layer library '%s'", path.c_str());
94
95 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
96 if (!dlhandle) {
97 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror());
98 return;
99 }
100
Jesse Hallaa410942016-01-17 13:07:10 -0800101 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
Jesse Hall80523e22016-01-06 16:47:54 -0800102 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
103 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -0800104 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
Jesse Hall80523e22016-01-06 16:47:54 -0800105 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
106 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties"));
Jesse Hallaa410942016-01-17 13:07:10 -0800107 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
108 reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
109 dlsym(dlhandle, "vkEnumerateDeviceLayerProperties"));
110 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
111 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
112 dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties"));
113 if (!((enumerate_instance_layers && enumerate_instance_extensions) ||
114 (enumerate_device_layers && enumerate_device_extensions))) {
115 ALOGV(
116 "layer library '%s' has neither instance nor device enumeraion "
117 "functions",
118 path.c_str());
Jesse Hall80523e22016-01-06 16:47:54 -0800119 dlclose(dlhandle);
120 return;
121 }
122
Jesse Hallaa410942016-01-17 13:07:10 -0800123 VkResult result;
124 uint32_t num_instance_layers = 0;
125 uint32_t num_device_layers = 0;
126 if (enumerate_instance_layers) {
127 result = enumerate_instance_layers(&num_instance_layers, nullptr);
128 if (result != VK_SUCCESS) {
129 ALOGW(
130 "vkEnumerateInstanceLayerProperties failed for library '%s': "
131 "%d",
132 path.c_str(), result);
133 dlclose(dlhandle);
134 return;
135 }
Jesse Hall80523e22016-01-06 16:47:54 -0800136 }
Jesse Hallaa410942016-01-17 13:07:10 -0800137 if (enumerate_device_layers) {
138 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
139 nullptr);
140 if (result != VK_SUCCESS) {
141 ALOGW(
142 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
143 path.c_str(), result);
144 dlclose(dlhandle);
145 return;
146 }
147 }
148 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
149 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
150 if (num_instance_layers > 0) {
151 result = enumerate_instance_layers(&num_instance_layers, properties);
152 if (result != VK_SUCCESS) {
153 ALOGW(
154 "vkEnumerateInstanceLayerProperties failed for library '%s': "
155 "%d",
156 path.c_str(), result);
157 dlclose(dlhandle);
158 return;
159 }
160 }
161 if (num_device_layers > 0) {
162 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
163 properties + num_instance_layers);
164 if (result != VK_SUCCESS) {
165 ALOGW(
166 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
167 path.c_str(), result);
168 dlclose(dlhandle);
169 return;
170 }
Jesse Hall80523e22016-01-06 16:47:54 -0800171 }
172
173 size_t library_idx = g_layer_libraries.size();
Jesse Hallaa410942016-01-17 13:07:10 -0800174 size_t prev_num_instance_layers = g_instance_layers.size();
175 size_t prev_num_device_layers = g_device_layers.size();
176 g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
177 g_device_layers.reserve(prev_num_device_layers + num_device_layers);
178 for (size_t i = 0; i < num_instance_layers; i++) {
179 const VkLayerProperties& props = properties[i];
180
Jesse Hall80523e22016-01-06 16:47:54 -0800181 Layer layer;
Jesse Hallaa410942016-01-17 13:07:10 -0800182 layer.properties = props;
Jesse Hall80523e22016-01-06 16:47:54 -0800183 layer.library_idx = library_idx;
184
Jesse Hallaa410942016-01-17 13:07:10 -0800185 if (enumerate_instance_extensions) {
186 uint32_t count = 0;
187 result =
188 enumerate_instance_extensions(props.layerName, &count, nullptr);
189 if (result != VK_SUCCESS) {
190 ALOGW(
191 "vkEnumerateInstanceExtensionProperties(%s) failed for "
192 "library "
193 "'%s': %d",
194 props.layerName, path.c_str(), result);
195 g_instance_layers.resize(prev_num_instance_layers);
196 dlclose(dlhandle);
197 return;
198 }
199 layer.extensions.resize(count);
200 result = enumerate_instance_extensions(props.layerName, &count,
201 layer.extensions.data());
202 if (result != VK_SUCCESS) {
203 ALOGW(
204 "vkEnumerateInstanceExtensionProperties(%s) failed for "
205 "library "
206 "'%s': %d",
207 props.layerName, path.c_str(), result);
208 g_instance_layers.resize(prev_num_instance_layers);
209 dlclose(dlhandle);
210 return;
211 }
Jesse Hall80523e22016-01-06 16:47:54 -0800212 }
213
Jesse Hallaa410942016-01-17 13:07:10 -0800214 g_instance_layers.push_back(layer);
Jesse Hallb1471272016-01-17 21:36:58 -0800215 ALOGV(" added instance layer '%s'", props.layerName);
Jesse Hallaa410942016-01-17 13:07:10 -0800216 }
217 for (size_t i = 0; i < num_device_layers; i++) {
218 const VkLayerProperties& props = properties[num_instance_layers + i];
219
220 Layer layer;
221 layer.properties = props;
222 layer.library_idx = library_idx;
223
224 if (enumerate_device_extensions) {
225 uint32_t count;
226 result = enumerate_device_extensions(
227 VK_NULL_HANDLE, props.layerName, &count, nullptr);
228 if (result != VK_SUCCESS) {
229 ALOGW(
230 "vkEnumerateDeviceExtensionProperties(%s) failed for "
231 "library "
232 "'%s': %d",
233 props.layerName, path.c_str(), result);
234 g_instance_layers.resize(prev_num_instance_layers);
235 g_device_layers.resize(prev_num_device_layers);
236 dlclose(dlhandle);
237 return;
238 }
239 layer.extensions.resize(count);
240 result =
241 enumerate_device_extensions(VK_NULL_HANDLE, props.layerName,
242 &count, layer.extensions.data());
243 if (result != VK_SUCCESS) {
244 ALOGW(
245 "vkEnumerateDeviceExtensionProperties(%s) failed for "
246 "library "
247 "'%s': %d",
248 props.layerName, path.c_str(), result);
249 g_instance_layers.resize(prev_num_instance_layers);
250 g_device_layers.resize(prev_num_device_layers);
251 dlclose(dlhandle);
252 return;
253 }
254 }
255
256 g_device_layers.push_back(layer);
Jesse Hallb1471272016-01-17 21:36:58 -0800257 ALOGV(" added device layer '%s'", props.layerName);
Jesse Hall80523e22016-01-06 16:47:54 -0800258 }
259
260 dlclose(dlhandle);
261
Chia-I Wu74349592016-04-18 12:08:39 +0800262 g_layer_libraries.emplace_back(path);
Jesse Hall80523e22016-01-06 16:47:54 -0800263}
264
265void DiscoverLayersInDirectory(const std::string& dir_path) {
266 ALOGV("looking for layers in '%s'", dir_path.c_str());
267
268 DIR* directory = opendir(dir_path.c_str());
269 if (!directory) {
270 int err = errno;
271 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)",
272 dir_path.c_str(), strerror(err), err);
273 return;
274 }
275
276 std::string path;
277 path.reserve(dir_path.size() + 20);
278 path.append(dir_path);
279 path.append("/");
280
281 struct dirent* entry;
282 while ((entry = readdir(directory))) {
283 size_t libname_len = strlen(entry->d_name);
Jesse Halla7ac76d2016-01-08 22:29:42 -0800284 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
Jesse Hall80523e22016-01-06 16:47:54 -0800285 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0)
286 continue;
287 path.append(entry->d_name);
288 AddLayerLibrary(path);
289 path.resize(dir_path.size() + 1);
290 }
291
292 closedir(directory);
293}
294
295void* GetLayerGetProcAddr(const Layer& layer,
296 const char* gpa_name,
297 size_t gpa_name_len) {
298 const LayerLibrary& library = g_layer_libraries[layer.library_idx];
299 void* gpa;
Jesse Hall30ac78b2016-01-11 21:29:40 -0800300 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
Jesse Hall80523e22016-01-06 16:47:54 -0800301 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
302 strcpy(name, layer.properties.layerName);
303 strcpy(name + layer_name_len, gpa_name);
304 if (!(gpa = dlsym(library.dlhandle, name))) {
305 strcpy(name, "vk");
306 strcpy(name + 2, gpa_name);
307 gpa = dlsym(library.dlhandle, name);
308 }
309 return gpa;
310}
311
Jesse Hallaa410942016-01-17 13:07:10 -0800312uint32_t EnumerateLayers(const std::vector<Layer>& layers,
313 uint32_t count,
314 VkLayerProperties* properties) {
315 uint32_t n = std::min(count, static_cast<uint32_t>(layers.size()));
Jesse Hall80523e22016-01-06 16:47:54 -0800316 for (uint32_t i = 0; i < n; i++) {
Jesse Hallaa410942016-01-17 13:07:10 -0800317 properties[i] = layers[i].properties;
Jesse Hall80523e22016-01-06 16:47:54 -0800318 }
Jesse Hallaa410942016-01-17 13:07:10 -0800319 return static_cast<uint32_t>(layers.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800320}
321
Jesse Hallaa410942016-01-17 13:07:10 -0800322void GetLayerExtensions(const std::vector<Layer>& layers,
323 const char* name,
Jesse Hall80523e22016-01-06 16:47:54 -0800324 const VkExtensionProperties** properties,
325 uint32_t* count) {
Jesse Hallaa410942016-01-17 13:07:10 -0800326 auto layer =
327 std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) {
328 return strcmp(entry.properties.layerName, name) == 0;
329 });
330 if (layer == layers.cend()) {
331 *properties = nullptr;
332 *count = 0;
333 } else {
334 *properties = layer->extensions.data();
335 *count = static_cast<uint32_t>(layer->extensions.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800336 }
337}
338
Jesse Hallaa410942016-01-17 13:07:10 -0800339LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) {
340 for (uint32_t id = 0; id < layers.size(); id++) {
Michael Lentined0b7cb52016-01-19 13:57:26 -0600341 if (strcmp(name, layers[id].properties.layerName) == 0) {
Jesse Hallaa410942016-01-17 13:07:10 -0800342 LayerLibrary& library = g_layer_libraries[layers[id].library_idx];
Jesse Hall80523e22016-01-06 16:47:54 -0800343 std::lock_guard<std::mutex> lock(g_library_mutex);
Chia-I Wufd0389f2016-04-18 12:11:00 +0800344 return LayerRef((library.Open()) ? &layers[id] : nullptr);
Jesse Hall80523e22016-01-06 16:47:54 -0800345 }
346 }
347 return LayerRef(nullptr);
348}
349
Jesse Hallaa410942016-01-17 13:07:10 -0800350} // anonymous namespace
351
Jesse Hallaa410942016-01-17 13:07:10 -0800352void DiscoverLayers() {
353 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0))
354 DiscoverLayersInDirectory("/data/local/debug/vulkan");
355 if (!LoaderData::GetInstance().layer_path.empty())
356 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str());
357}
358
359uint32_t EnumerateInstanceLayers(uint32_t count,
360 VkLayerProperties* properties) {
361 return EnumerateLayers(g_instance_layers, count, properties);
362}
363
364uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) {
365 return EnumerateLayers(g_device_layers, count, properties);
366}
367
368void GetInstanceLayerExtensions(const char* name,
369 const VkExtensionProperties** properties,
370 uint32_t* count) {
371 GetLayerExtensions(g_instance_layers, name, properties, count);
372}
373
374void GetDeviceLayerExtensions(const char* name,
375 const VkExtensionProperties** properties,
376 uint32_t* count) {
377 GetLayerExtensions(g_device_layers, name, properties, count);
378}
379
380LayerRef GetInstanceLayerRef(const char* name) {
381 return GetLayerRef(g_instance_layers, name);
382}
383
384LayerRef GetDeviceLayerRef(const char* name) {
385 return GetLayerRef(g_device_layers, name);
386}
387
Jesse Hall80523e22016-01-06 16:47:54 -0800388LayerRef::LayerRef(Layer* layer) : layer_(layer) {}
389
390LayerRef::~LayerRef() {
391 if (layer_) {
392 LayerLibrary& library = g_layer_libraries[layer_->library_idx];
393 std::lock_guard<std::mutex> lock(g_library_mutex);
394 if (--library.refcount == 0) {
Michael Lentine54e6f082016-01-20 11:25:28 -0600395 ALOGV("Closing library %s", library.path.c_str());
Jesse Hall80523e22016-01-06 16:47:54 -0800396 dlclose(library.dlhandle);
397 library.dlhandle = nullptr;
398 }
Michael Lentine54e6f082016-01-20 11:25:28 -0600399 ALOGV("Refcount on destruction is %zu", library.refcount);
Jesse Hall80523e22016-01-06 16:47:54 -0800400 }
401}
402
Michael Lentine57036832016-03-04 11:03:35 -0600403const char* LayerRef::GetName() const {
Courtney Goeltzenleuchtereff63112016-02-08 20:12:59 -0700404 return layer_->properties.layerName;
405}
406
407uint32_t LayerRef::GetSpecVersion() {
408 return layer_->properties.specVersion;
409}
410
Michael Lentine54e6f082016-01-20 11:25:28 -0600411LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {
412 other.layer_ = nullptr;
413}
Jesse Hall80523e22016-01-06 16:47:54 -0800414
415PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
416 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
417 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
418 : nullptr;
419}
420
421PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
422 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
423 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
424 : nullptr;
425}
426
Jesse Hallb1471272016-01-17 21:36:58 -0800427bool LayerRef::SupportsExtension(const char* name) const {
428 return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(),
429 [=](const VkExtensionProperties& ext) {
430 return strcmp(ext.extensionName, name) == 0;
431 }) != layer_->extensions.cend();
432}
433
Chia-I Wuc96880f2016-03-26 06:56:45 +0800434} // namespace api
Jesse Hall80523e22016-01-06 16:47:54 -0800435} // namespace vulkan