layers_extensions.cpp revision c96880f2cd1d34ffb9e3d10d80f0a3ddcc5579a8
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 "layers_extensions.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 31// 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 37// 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 50namespace vulkan { 51namespace api { 52 53struct Layer { 54 VkLayerProperties properties; 55 size_t library_idx; 56 std::vector<VkExtensionProperties> extensions; 57}; 58 59namespace { 60 61std::mutex g_library_mutex; 62struct LayerLibrary { 63 std::string path; 64 void* dlhandle; 65 size_t refcount; 66}; 67std::vector<LayerLibrary> g_layer_libraries; 68std::vector<Layer> g_instance_layers; 69std::vector<Layer> g_device_layers; 70 71void AddLayerLibrary(const std::string& path) { 72 ALOGV("examining layer library '%s'", path.c_str()); 73 74 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); 75 if (!dlhandle) { 76 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror()); 77 return; 78 } 79 80 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers = 81 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>( 82 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties")); 83 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions = 84 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>( 85 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties")); 86 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers = 87 reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>( 88 dlsym(dlhandle, "vkEnumerateDeviceLayerProperties")); 89 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions = 90 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>( 91 dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties")); 92 if (!((enumerate_instance_layers && enumerate_instance_extensions) || 93 (enumerate_device_layers && enumerate_device_extensions))) { 94 ALOGV( 95 "layer library '%s' has neither instance nor device enumeraion " 96 "functions", 97 path.c_str()); 98 dlclose(dlhandle); 99 return; 100 } 101 102 VkResult result; 103 uint32_t num_instance_layers = 0; 104 uint32_t num_device_layers = 0; 105 if (enumerate_instance_layers) { 106 result = enumerate_instance_layers(&num_instance_layers, nullptr); 107 if (result != VK_SUCCESS) { 108 ALOGW( 109 "vkEnumerateInstanceLayerProperties failed for library '%s': " 110 "%d", 111 path.c_str(), result); 112 dlclose(dlhandle); 113 return; 114 } 115 } 116 if (enumerate_device_layers) { 117 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 118 nullptr); 119 if (result != VK_SUCCESS) { 120 ALOGW( 121 "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 122 path.c_str(), result); 123 dlclose(dlhandle); 124 return; 125 } 126 } 127 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca( 128 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); 129 if (num_instance_layers > 0) { 130 result = enumerate_instance_layers(&num_instance_layers, properties); 131 if (result != VK_SUCCESS) { 132 ALOGW( 133 "vkEnumerateInstanceLayerProperties failed for library '%s': " 134 "%d", 135 path.c_str(), result); 136 dlclose(dlhandle); 137 return; 138 } 139 } 140 if (num_device_layers > 0) { 141 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 142 properties + num_instance_layers); 143 if (result != VK_SUCCESS) { 144 ALOGW( 145 "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 146 path.c_str(), result); 147 dlclose(dlhandle); 148 return; 149 } 150 } 151 152 size_t library_idx = g_layer_libraries.size(); 153 size_t prev_num_instance_layers = g_instance_layers.size(); 154 size_t prev_num_device_layers = g_device_layers.size(); 155 g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers); 156 g_device_layers.reserve(prev_num_device_layers + num_device_layers); 157 for (size_t i = 0; i < num_instance_layers; i++) { 158 const VkLayerProperties& props = properties[i]; 159 160 Layer layer; 161 layer.properties = props; 162 layer.library_idx = library_idx; 163 164 if (enumerate_instance_extensions) { 165 uint32_t count = 0; 166 result = 167 enumerate_instance_extensions(props.layerName, &count, nullptr); 168 if (result != VK_SUCCESS) { 169 ALOGW( 170 "vkEnumerateInstanceExtensionProperties(%s) failed for " 171 "library " 172 "'%s': %d", 173 props.layerName, path.c_str(), result); 174 g_instance_layers.resize(prev_num_instance_layers); 175 dlclose(dlhandle); 176 return; 177 } 178 layer.extensions.resize(count); 179 result = enumerate_instance_extensions(props.layerName, &count, 180 layer.extensions.data()); 181 if (result != VK_SUCCESS) { 182 ALOGW( 183 "vkEnumerateInstanceExtensionProperties(%s) failed for " 184 "library " 185 "'%s': %d", 186 props.layerName, path.c_str(), result); 187 g_instance_layers.resize(prev_num_instance_layers); 188 dlclose(dlhandle); 189 return; 190 } 191 } 192 193 g_instance_layers.push_back(layer); 194 ALOGV(" added instance layer '%s'", props.layerName); 195 } 196 for (size_t i = 0; i < num_device_layers; i++) { 197 const VkLayerProperties& props = properties[num_instance_layers + i]; 198 199 Layer layer; 200 layer.properties = props; 201 layer.library_idx = library_idx; 202 203 if (enumerate_device_extensions) { 204 uint32_t count; 205 result = enumerate_device_extensions( 206 VK_NULL_HANDLE, props.layerName, &count, nullptr); 207 if (result != VK_SUCCESS) { 208 ALOGW( 209 "vkEnumerateDeviceExtensionProperties(%s) failed for " 210 "library " 211 "'%s': %d", 212 props.layerName, path.c_str(), result); 213 g_instance_layers.resize(prev_num_instance_layers); 214 g_device_layers.resize(prev_num_device_layers); 215 dlclose(dlhandle); 216 return; 217 } 218 layer.extensions.resize(count); 219 result = 220 enumerate_device_extensions(VK_NULL_HANDLE, props.layerName, 221 &count, layer.extensions.data()); 222 if (result != VK_SUCCESS) { 223 ALOGW( 224 "vkEnumerateDeviceExtensionProperties(%s) failed for " 225 "library " 226 "'%s': %d", 227 props.layerName, path.c_str(), result); 228 g_instance_layers.resize(prev_num_instance_layers); 229 g_device_layers.resize(prev_num_device_layers); 230 dlclose(dlhandle); 231 return; 232 } 233 } 234 235 g_device_layers.push_back(layer); 236 ALOGV(" added device layer '%s'", props.layerName); 237 } 238 239 dlclose(dlhandle); 240 241 g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0}); 242} 243 244void DiscoverLayersInDirectory(const std::string& dir_path) { 245 ALOGV("looking for layers in '%s'", dir_path.c_str()); 246 247 DIR* directory = opendir(dir_path.c_str()); 248 if (!directory) { 249 int err = errno; 250 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)", 251 dir_path.c_str(), strerror(err), err); 252 return; 253 } 254 255 std::string path; 256 path.reserve(dir_path.size() + 20); 257 path.append(dir_path); 258 path.append("/"); 259 260 struct dirent* entry; 261 while ((entry = readdir(directory))) { 262 size_t libname_len = strlen(entry->d_name); 263 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 || 264 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0) 265 continue; 266 path.append(entry->d_name); 267 AddLayerLibrary(path); 268 path.resize(dir_path.size() + 1); 269 } 270 271 closedir(directory); 272} 273 274void* GetLayerGetProcAddr(const Layer& layer, 275 const char* gpa_name, 276 size_t gpa_name_len) { 277 const LayerLibrary& library = g_layer_libraries[layer.library_idx]; 278 void* gpa; 279 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName)); 280 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); 281 strcpy(name, layer.properties.layerName); 282 strcpy(name + layer_name_len, gpa_name); 283 if (!(gpa = dlsym(library.dlhandle, name))) { 284 strcpy(name, "vk"); 285 strcpy(name + 2, gpa_name); 286 gpa = dlsym(library.dlhandle, name); 287 } 288 return gpa; 289} 290 291uint32_t EnumerateLayers(const std::vector<Layer>& layers, 292 uint32_t count, 293 VkLayerProperties* properties) { 294 uint32_t n = std::min(count, static_cast<uint32_t>(layers.size())); 295 for (uint32_t i = 0; i < n; i++) { 296 properties[i] = layers[i].properties; 297 } 298 return static_cast<uint32_t>(layers.size()); 299} 300 301void GetLayerExtensions(const std::vector<Layer>& layers, 302 const char* name, 303 const VkExtensionProperties** properties, 304 uint32_t* count) { 305 auto layer = 306 std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) { 307 return strcmp(entry.properties.layerName, name) == 0; 308 }); 309 if (layer == layers.cend()) { 310 *properties = nullptr; 311 *count = 0; 312 } else { 313 *properties = layer->extensions.data(); 314 *count = static_cast<uint32_t>(layer->extensions.size()); 315 } 316} 317 318LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) { 319 for (uint32_t id = 0; id < layers.size(); id++) { 320 if (strcmp(name, layers[id].properties.layerName) == 0) { 321 LayerLibrary& library = g_layer_libraries[layers[id].library_idx]; 322 std::lock_guard<std::mutex> lock(g_library_mutex); 323 if (library.refcount++ == 0) { 324 library.dlhandle = 325 dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL); 326 ALOGV("Opening library %s", library.path.c_str()); 327 if (!library.dlhandle) { 328 ALOGE("failed to load layer library '%s': %s", 329 library.path.c_str(), dlerror()); 330 library.refcount = 0; 331 return LayerRef(nullptr); 332 } 333 } 334 ALOGV("Refcount on activate is %zu", library.refcount); 335 return LayerRef(&layers[id]); 336 } 337 } 338 return LayerRef(nullptr); 339} 340 341} // anonymous namespace 342 343void DiscoverLayers() { 344 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) 345 DiscoverLayersInDirectory("/data/local/debug/vulkan"); 346 if (!LoaderData::GetInstance().layer_path.empty()) 347 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str()); 348} 349 350uint32_t EnumerateInstanceLayers(uint32_t count, 351 VkLayerProperties* properties) { 352 return EnumerateLayers(g_instance_layers, count, properties); 353} 354 355uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) { 356 return EnumerateLayers(g_device_layers, count, properties); 357} 358 359void GetInstanceLayerExtensions(const char* name, 360 const VkExtensionProperties** properties, 361 uint32_t* count) { 362 GetLayerExtensions(g_instance_layers, name, properties, count); 363} 364 365void GetDeviceLayerExtensions(const char* name, 366 const VkExtensionProperties** properties, 367 uint32_t* count) { 368 GetLayerExtensions(g_device_layers, name, properties, count); 369} 370 371LayerRef GetInstanceLayerRef(const char* name) { 372 return GetLayerRef(g_instance_layers, name); 373} 374 375LayerRef GetDeviceLayerRef(const char* name) { 376 return GetLayerRef(g_device_layers, name); 377} 378 379LayerRef::LayerRef(Layer* layer) : layer_(layer) {} 380 381LayerRef::~LayerRef() { 382 if (layer_) { 383 LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 384 std::lock_guard<std::mutex> lock(g_library_mutex); 385 if (--library.refcount == 0) { 386 ALOGV("Closing library %s", library.path.c_str()); 387 dlclose(library.dlhandle); 388 library.dlhandle = nullptr; 389 } 390 ALOGV("Refcount on destruction is %zu", library.refcount); 391 } 392} 393 394const char* LayerRef::GetName() const { 395 return layer_->properties.layerName; 396} 397 398uint32_t LayerRef::GetSpecVersion() { 399 return layer_->properties.specVersion; 400} 401 402LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) { 403 other.layer_ = nullptr; 404} 405 406PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 407 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 408 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 409 : nullptr; 410} 411 412PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 413 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 414 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 415 : nullptr; 416} 417 418bool LayerRef::SupportsExtension(const char* name) const { 419 return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(), 420 [=](const VkExtensionProperties& ext) { 421 return strcmp(ext.extensionName, name) == 0; 422 }) != layer_->extensions.cend(); 423} 424 425} // namespace api 426} // namespace vulkan 427