layers_extensions.cpp revision d0b7cb566288a4f6646e356a17188b7922ba5740
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 "loader.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 31using namespace vulkan; 32 33// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and 34// not a good long-term solution. Having a hard-coded enum of extensions is 35// bad, of course. Representing sets of extensions (requested, supported, etc.) 36// as a bitset isn't necessarily bad, if the mapping from extension to bit were 37// dynamic. Need to rethink this completely when there's a little more time. 38 39// TODO(jessehall): This file currently builds up global data structures as it 40// loads, and never cleans them up. This means we're doing heap allocations 41// without going through an app-provided allocator, but worse, we'll leak those 42// allocations if the loader is unloaded. 43// 44// We should allocate "enough" BSS space, and suballocate from there. Will 45// probably want to intern strings, etc., and will need some custom/manual data 46// structures. 47 48// TODO(jessehall): Currently we have separate lists for instance and device 49// layers. Most layers are both; we should use one entry for each layer name, 50// with a mask saying what kind(s) it is. 51 52namespace vulkan { 53struct Layer { 54 VkLayerProperties properties; 55 size_t library_idx; 56 std::vector<VkExtensionProperties> extensions; 57}; 58} // namespace vulkan 59 60namespace { 61 62std::mutex g_library_mutex; 63struct LayerLibrary { 64 std::string path; 65 void* dlhandle; 66 size_t refcount; 67}; 68std::vector<LayerLibrary> g_layer_libraries; 69std::vector<Layer> g_instance_layers; 70std::vector<Layer> g_device_layers; 71 72void AddLayerLibrary(const std::string& path) { 73 ALOGV("examining layer library '%s'", path.c_str()); 74 75 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); 76 if (!dlhandle) { 77 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror()); 78 return; 79 } 80 81 PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers = 82 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>( 83 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties")); 84 PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions = 85 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>( 86 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties")); 87 PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers = 88 reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>( 89 dlsym(dlhandle, "vkEnumerateDeviceLayerProperties")); 90 PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions = 91 reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>( 92 dlsym(dlhandle, "vkEnumerateDeviceExtensionProperties")); 93 if (!((enumerate_instance_layers && enumerate_instance_extensions) || 94 (enumerate_device_layers && enumerate_device_extensions))) { 95 ALOGV( 96 "layer library '%s' has neither instance nor device enumeraion " 97 "functions", 98 path.c_str()); 99 dlclose(dlhandle); 100 return; 101 } 102 103 VkResult result; 104 uint32_t num_instance_layers = 0; 105 uint32_t num_device_layers = 0; 106 if (enumerate_instance_layers) { 107 result = enumerate_instance_layers(&num_instance_layers, nullptr); 108 if (result != VK_SUCCESS) { 109 ALOGW( 110 "vkEnumerateInstanceLayerProperties failed for library '%s': " 111 "%d", 112 path.c_str(), result); 113 dlclose(dlhandle); 114 return; 115 } 116 } 117 if (enumerate_device_layers) { 118 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 119 nullptr); 120 if (result != VK_SUCCESS) { 121 ALOGW( 122 "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 123 path.c_str(), result); 124 dlclose(dlhandle); 125 return; 126 } 127 } 128 VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca( 129 (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); 130 if (num_instance_layers > 0) { 131 result = enumerate_instance_layers(&num_instance_layers, properties); 132 if (result != VK_SUCCESS) { 133 ALOGW( 134 "vkEnumerateInstanceLayerProperties failed for library '%s': " 135 "%d", 136 path.c_str(), result); 137 dlclose(dlhandle); 138 return; 139 } 140 } 141 if (num_device_layers > 0) { 142 result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 143 properties + num_instance_layers); 144 if (result != VK_SUCCESS) { 145 ALOGW( 146 "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 147 path.c_str(), result); 148 dlclose(dlhandle); 149 return; 150 } 151 } 152 153 size_t library_idx = g_layer_libraries.size(); 154 size_t prev_num_instance_layers = g_instance_layers.size(); 155 size_t prev_num_device_layers = g_device_layers.size(); 156 g_instance_layers.reserve(prev_num_instance_layers + num_instance_layers); 157 g_device_layers.reserve(prev_num_device_layers + num_device_layers); 158 for (size_t i = 0; i < num_instance_layers; i++) { 159 const VkLayerProperties& props = properties[i]; 160 161 Layer layer; 162 layer.properties = props; 163 layer.library_idx = library_idx; 164 165 if (enumerate_instance_extensions) { 166 uint32_t count = 0; 167 result = 168 enumerate_instance_extensions(props.layerName, &count, nullptr); 169 if (result != VK_SUCCESS) { 170 ALOGW( 171 "vkEnumerateInstanceExtensionProperties(%s) failed for " 172 "library " 173 "'%s': %d", 174 props.layerName, path.c_str(), result); 175 g_instance_layers.resize(prev_num_instance_layers); 176 dlclose(dlhandle); 177 return; 178 } 179 layer.extensions.resize(count); 180 result = enumerate_instance_extensions(props.layerName, &count, 181 layer.extensions.data()); 182 if (result != VK_SUCCESS) { 183 ALOGW( 184 "vkEnumerateInstanceExtensionProperties(%s) failed for " 185 "library " 186 "'%s': %d", 187 props.layerName, path.c_str(), result); 188 g_instance_layers.resize(prev_num_instance_layers); 189 dlclose(dlhandle); 190 return; 191 } 192 } 193 194 g_instance_layers.push_back(layer); 195 ALOGV(" added instance layer '%s'", props.layerName); 196 } 197 for (size_t i = 0; i < num_device_layers; i++) { 198 const VkLayerProperties& props = properties[num_instance_layers + i]; 199 200 Layer layer; 201 layer.properties = props; 202 layer.library_idx = library_idx; 203 204 if (enumerate_device_extensions) { 205 uint32_t count; 206 result = enumerate_device_extensions( 207 VK_NULL_HANDLE, props.layerName, &count, nullptr); 208 if (result != VK_SUCCESS) { 209 ALOGW( 210 "vkEnumerateDeviceExtensionProperties(%s) failed for " 211 "library " 212 "'%s': %d", 213 props.layerName, path.c_str(), result); 214 g_instance_layers.resize(prev_num_instance_layers); 215 g_device_layers.resize(prev_num_device_layers); 216 dlclose(dlhandle); 217 return; 218 } 219 layer.extensions.resize(count); 220 result = 221 enumerate_device_extensions(VK_NULL_HANDLE, props.layerName, 222 &count, layer.extensions.data()); 223 if (result != VK_SUCCESS) { 224 ALOGW( 225 "vkEnumerateDeviceExtensionProperties(%s) failed for " 226 "library " 227 "'%s': %d", 228 props.layerName, path.c_str(), result); 229 g_instance_layers.resize(prev_num_instance_layers); 230 g_device_layers.resize(prev_num_device_layers); 231 dlclose(dlhandle); 232 return; 233 } 234 } 235 236 g_device_layers.push_back(layer); 237 ALOGV(" added device layer '%s'", props.layerName); 238 } 239 240 dlclose(dlhandle); 241 242 g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0}); 243} 244 245void DiscoverLayersInDirectory(const std::string& dir_path) { 246 ALOGV("looking for layers in '%s'", dir_path.c_str()); 247 248 DIR* directory = opendir(dir_path.c_str()); 249 if (!directory) { 250 int err = errno; 251 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)", 252 dir_path.c_str(), strerror(err), err); 253 return; 254 } 255 256 std::string path; 257 path.reserve(dir_path.size() + 20); 258 path.append(dir_path); 259 path.append("/"); 260 261 struct dirent* entry; 262 while ((entry = readdir(directory))) { 263 size_t libname_len = strlen(entry->d_name); 264 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 || 265 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0) 266 continue; 267 path.append(entry->d_name); 268 AddLayerLibrary(path); 269 path.resize(dir_path.size() + 1); 270 } 271 272 closedir(directory); 273} 274 275void* GetLayerGetProcAddr(const Layer& layer, 276 const char* gpa_name, 277 size_t gpa_name_len) { 278 const LayerLibrary& library = g_layer_libraries[layer.library_idx]; 279 void* gpa; 280 size_t layer_name_len = std::max(size_t{2}, strlen(layer.properties.layerName)); 281 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); 282 strcpy(name, layer.properties.layerName); 283 strcpy(name + layer_name_len, gpa_name); 284 if (!(gpa = dlsym(library.dlhandle, name))) { 285 strcpy(name, "vk"); 286 strcpy(name + 2, gpa_name); 287 gpa = dlsym(library.dlhandle, name); 288 } 289 return gpa; 290} 291 292uint32_t EnumerateLayers(const std::vector<Layer>& layers, 293 uint32_t count, 294 VkLayerProperties* properties) { 295 uint32_t n = std::min(count, static_cast<uint32_t>(layers.size())); 296 for (uint32_t i = 0; i < n; i++) { 297 properties[i] = layers[i].properties; 298 } 299 return static_cast<uint32_t>(layers.size()); 300} 301 302void GetLayerExtensions(const std::vector<Layer>& layers, 303 const char* name, 304 const VkExtensionProperties** properties, 305 uint32_t* count) { 306 auto layer = 307 std::find_if(layers.cbegin(), layers.cend(), [=](const Layer& entry) { 308 return strcmp(entry.properties.layerName, name) == 0; 309 }); 310 if (layer == layers.cend()) { 311 *properties = nullptr; 312 *count = 0; 313 } else { 314 *properties = layer->extensions.data(); 315 *count = static_cast<uint32_t>(layer->extensions.size()); 316 } 317} 318 319LayerRef GetLayerRef(std::vector<Layer>& layers, const char* name) { 320 for (uint32_t id = 0; id < layers.size(); id++) { 321 if (strcmp(name, layers[id].properties.layerName) == 0) { 322 LayerLibrary& library = g_layer_libraries[layers[id].library_idx]; 323 std::lock_guard<std::mutex> lock(g_library_mutex); 324 if (library.refcount++ == 0) { 325 library.dlhandle = 326 dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL); 327 if (!library.dlhandle) { 328 ALOGE("failed to load layer library '%s': %s", 329 library.path.c_str(), dlerror()); 330 library.refcount = 0; 331 return LayerRef(nullptr); 332 } 333 } 334 return LayerRef(&layers[id]); 335 } 336 } 337 return LayerRef(nullptr); 338} 339 340} // anonymous namespace 341 342namespace vulkan { 343 344void DiscoverLayers() { 345 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) 346 DiscoverLayersInDirectory("/data/local/debug/vulkan"); 347 if (!LoaderData::GetInstance().layer_path.empty()) 348 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str()); 349} 350 351uint32_t EnumerateInstanceLayers(uint32_t count, 352 VkLayerProperties* properties) { 353 return EnumerateLayers(g_instance_layers, count, properties); 354} 355 356uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) { 357 return EnumerateLayers(g_device_layers, count, properties); 358} 359 360void GetInstanceLayerExtensions(const char* name, 361 const VkExtensionProperties** properties, 362 uint32_t* count) { 363 GetLayerExtensions(g_instance_layers, name, properties, count); 364} 365 366void GetDeviceLayerExtensions(const char* name, 367 const VkExtensionProperties** properties, 368 uint32_t* count) { 369 GetLayerExtensions(g_device_layers, name, properties, count); 370} 371 372LayerRef GetInstanceLayerRef(const char* name) { 373 return GetLayerRef(g_instance_layers, name); 374} 375 376LayerRef GetDeviceLayerRef(const char* name) { 377 return GetLayerRef(g_device_layers, name); 378} 379 380LayerRef::LayerRef(Layer* layer) : layer_(layer) {} 381 382LayerRef::~LayerRef() { 383 if (layer_) { 384 LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 385 std::lock_guard<std::mutex> lock(g_library_mutex); 386 if (--library.refcount == 0) { 387 dlclose(library.dlhandle); 388 library.dlhandle = nullptr; 389 } 390 } 391} 392 393LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {} 394 395PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 396 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 397 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 398 : nullptr; 399} 400 401PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 402 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 403 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 404 : nullptr; 405} 406 407bool LayerRef::SupportsExtension(const char* name) const { 408 return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(), 409 [=](const VkExtensionProperties& ext) { 410 return strcmp(ext.extensionName, name) == 0; 411 }) != layer_->extensions.cend(); 412} 413 414InstanceExtension InstanceExtensionFromName(const char* name) { 415 if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0) 416 return kKHR_surface; 417 if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) 418 return kKHR_android_surface; 419 if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) 420 return kEXT_debug_report; 421 return kInstanceExtensionCount; 422} 423 424DeviceExtension DeviceExtensionFromName(const char* name) { 425 if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) 426 return kKHR_swapchain; 427 if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0) 428 return kANDROID_native_buffer; 429 return kDeviceExtensionCount; 430} 431 432} // namespace vulkan 433