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