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