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