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