blob: 2c1b1829bb26895ff3ba72f4ba6312a77cf2b225 [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 Hall504db7f2016-01-14 15:53:57 -080017// #define LOG_NDEBUG 0
Jesse Hall80523e22016-01-06 16:47:54 -080018
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);
Jesse Halla7ac76d2016-01-08 22:29:42 -0800162 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 ||
Jesse Hall80523e22016-01-06 16:47:54 -0800163 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;
Jesse Hall30ac78b2016-01-11 21:29:40 -0800178 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName));
Jesse Hall80523e22016-01-06 16:47:54 -0800179 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) {
Jesse Hall30ac78b2016-01-11 21:29:40 -0800202 uint32_t n = std::min(count, static_cast<uint32_t>(g_layers.size()));
Jesse Hall80523e22016-01-06 16:47:54 -0800203 for (uint32_t i = 0; i < n; i++) {
204 properties[i] = g_layers[i].properties;
205 }
Jesse Hall30ac78b2016-01-11 21:29:40 -0800206 return static_cast<uint32_t>(g_layers.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800207}
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();
Jesse Hall30ac78b2016-01-11 21:29:40 -0800216 *count = static_cast<uint32_t>(layer.extensions.size());
Jesse Hall80523e22016-01-06 16:47:54 -0800217 }
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
268} // namespace vulkan