layers_extensions.cpp revision d6e6f51426c566cd67ed765e5c4b206a063aaa30
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 333void* GetLayerGetProcAddr(const Layer& layer, 334 const char* gpa_name, 335 size_t gpa_name_len) { 336 const LayerLibrary& library = g_layer_libraries[layer.library_idx]; 337 return library.GetGPA(layer, gpa_name, gpa_name_len); 338} 339 340} // anonymous namespace 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 GetLayerCount() { 350 return static_cast<uint32_t>(g_instance_layers.size()); 351} 352 353const Layer& GetLayer(uint32_t index) { 354 return g_instance_layers[index]; 355} 356 357const Layer* FindLayer(const char* name) { 358 auto layer = 359 std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(), 360 [=](const Layer& entry) { 361 return strcmp(entry.properties.layerName, name) == 0; 362 }); 363 return (layer != g_instance_layers.cend()) ? &*layer : nullptr; 364} 365 366const VkLayerProperties& GetLayerProperties(const Layer& layer) { 367 return layer.properties; 368} 369 370bool IsLayerGlobal(const Layer& layer) { 371 return layer.is_global; 372} 373 374const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer, 375 uint32_t& count) { 376 count = static_cast<uint32_t>(layer.instance_extensions.size()); 377 return layer.instance_extensions.data(); 378} 379 380const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer, 381 uint32_t& count) { 382 count = static_cast<uint32_t>(layer.device_extensions.size()); 383 return layer.device_extensions.data(); 384} 385 386LayerRef GetInstanceLayerRef(const Layer& layer) { 387 LayerLibrary& library = g_layer_libraries[layer.library_idx]; 388 return LayerRef((library.Open()) ? &layer : nullptr, true); 389} 390 391LayerRef GetDeviceLayerRef(const Layer& layer) { 392 LayerLibrary& library = g_layer_libraries[layer.library_idx]; 393 return LayerRef((layer.is_global && library.Open()) ? &layer : nullptr, 394 false); 395} 396 397LayerRef::LayerRef(const Layer* layer, bool is_instance) 398 : layer_(layer), is_instance_(is_instance) {} 399 400LayerRef::~LayerRef() { 401 if (layer_) { 402 LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 403 library.Close(); 404 } 405} 406 407const char* LayerRef::GetName() const { 408 return layer_->properties.layerName; 409} 410 411uint32_t LayerRef::GetSpecVersion() const { 412 return layer_->properties.specVersion; 413} 414 415LayerRef::LayerRef(LayerRef&& other) 416 : layer_(other.layer_), is_instance_(other.is_instance_) { 417 other.layer_ = nullptr; 418} 419 420PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 421 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 422 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 423 : nullptr; 424} 425 426PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 427 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 428 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 429 : nullptr; 430} 431 432bool LayerRef::SupportsExtension(const char* name) const { 433 const auto& extensions = (is_instance_) ? layer_->instance_extensions 434 : layer_->device_extensions; 435 return std::find_if(extensions.cbegin(), extensions.cend(), 436 [=](const VkExtensionProperties& ext) { 437 return strcmp(ext.extensionName, name) == 0; 438 }) != extensions.cend(); 439} 440 441} // namespace api 442} // namespace vulkan 443