layers_extensions.cpp revision eff631189b135a9579a7f8510f9b1ccadd6fb4f9
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 ALOGV("Opening library %s", library.path.c_str()); 328 if (!library.dlhandle) { 329 ALOGE("failed to load layer library '%s': %s", 330 library.path.c_str(), dlerror()); 331 library.refcount = 0; 332 return LayerRef(nullptr); 333 } 334 } 335 ALOGV("Refcount on activate is %zu", library.refcount); 336 return LayerRef(&layers[id]); 337 } 338 } 339 return LayerRef(nullptr); 340} 341 342} // anonymous namespace 343 344namespace vulkan { 345 346void DiscoverLayers() { 347 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) 348 DiscoverLayersInDirectory("/data/local/debug/vulkan"); 349 if (!LoaderData::GetInstance().layer_path.empty()) 350 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str()); 351} 352 353uint32_t EnumerateInstanceLayers(uint32_t count, 354 VkLayerProperties* properties) { 355 return EnumerateLayers(g_instance_layers, count, properties); 356} 357 358uint32_t EnumerateDeviceLayers(uint32_t count, VkLayerProperties* properties) { 359 return EnumerateLayers(g_device_layers, count, properties); 360} 361 362void GetInstanceLayerExtensions(const char* name, 363 const VkExtensionProperties** properties, 364 uint32_t* count) { 365 GetLayerExtensions(g_instance_layers, name, properties, count); 366} 367 368void GetDeviceLayerExtensions(const char* name, 369 const VkExtensionProperties** properties, 370 uint32_t* count) { 371 GetLayerExtensions(g_device_layers, name, properties, count); 372} 373 374LayerRef GetInstanceLayerRef(const char* name) { 375 return GetLayerRef(g_instance_layers, name); 376} 377 378LayerRef GetDeviceLayerRef(const char* name) { 379 return GetLayerRef(g_device_layers, name); 380} 381 382LayerRef::LayerRef(Layer* layer) : layer_(layer) {} 383 384LayerRef::~LayerRef() { 385 if (layer_) { 386 LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 387 std::lock_guard<std::mutex> lock(g_library_mutex); 388 if (--library.refcount == 0) { 389 ALOGV("Closing library %s", library.path.c_str()); 390 dlclose(library.dlhandle); 391 library.dlhandle = nullptr; 392 } 393 ALOGV("Refcount on destruction is %zu", library.refcount); 394 } 395} 396 397const char* LayerRef::GetName() { 398 return layer_->properties.layerName; 399} 400 401uint32_t LayerRef::GetSpecVersion() { 402 return layer_->properties.specVersion; 403} 404 405LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) { 406 other.layer_ = nullptr; 407} 408 409PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 410 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 411 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 412 : nullptr; 413} 414 415PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 416 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 417 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 418 : nullptr; 419} 420 421bool LayerRef::SupportsExtension(const char* name) const { 422 return std::find_if(layer_->extensions.cbegin(), layer_->extensions.cend(), 423 [=](const VkExtensionProperties& ext) { 424 return strcmp(ext.extensionName, name) == 0; 425 }) != layer_->extensions.cend(); 426} 427 428InstanceExtension InstanceExtensionFromName(const char* name) { 429 if (strcmp(name, VK_KHR_SURFACE_EXTENSION_NAME) == 0) 430 return kKHR_surface; 431 if (strcmp(name, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME) == 0) 432 return kKHR_android_surface; 433 if (strcmp(name, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) 434 return kEXT_debug_report; 435 return kInstanceExtensionCount; 436} 437 438DeviceExtension DeviceExtensionFromName(const char* name) { 439 if (strcmp(name, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) 440 return kKHR_swapchain; 441 if (strcmp(name, VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME) == 0) 442 return kANDROID_native_buffer; 443 return kDeviceExtensionCount; 444} 445 446} // namespace vulkan 447