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