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