layers_extensions.cpp revision a7ac76df54c30e771ecfd05cdd2b52209af71470
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 33namespace vulkan { 34struct Layer { 35 VkLayerProperties properties; 36 size_t library_idx; 37 std::vector<VkExtensionProperties> extensions; 38}; 39} // namespace vulkan 40 41namespace { 42 43std::mutex g_library_mutex; 44struct LayerLibrary { 45 std::string path; 46 void* dlhandle; 47 size_t refcount; 48}; 49std::vector<LayerLibrary> g_layer_libraries; 50std::vector<Layer> g_layers; 51 52void AddLayerLibrary(const std::string& path) { 53 ALOGV("examining layer library '%s'", path.c_str()); 54 55 void* dlhandle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); 56 if (!dlhandle) { 57 ALOGW("failed to load layer library '%s': %s", path.c_str(), dlerror()); 58 return; 59 } 60 61 PFN_vkEnumerateInstanceLayerProperties enumerate_layer_properties = 62 reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>( 63 dlsym(dlhandle, "vkEnumerateInstanceLayerProperties")); 64 if (!enumerate_layer_properties) { 65 ALOGW( 66 "failed to find vkEnumerateInstanceLayerProperties in library " 67 "'%s': %s", 68 path.c_str(), dlerror()); 69 dlclose(dlhandle); 70 return; 71 } 72 PFN_vkEnumerateInstanceExtensionProperties enumerate_extension_properties = 73 reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>( 74 dlsym(dlhandle, "vkEnumerateInstanceExtensionProperties")); 75 if (!enumerate_extension_properties) { 76 ALOGW( 77 "failed to find vkEnumerateInstanceExtensionProperties in library " 78 "'%s': %s", 79 path.c_str(), dlerror()); 80 dlclose(dlhandle); 81 return; 82 } 83 84 uint32_t layer_count; 85 VkResult result = enumerate_layer_properties(&layer_count, nullptr); 86 if (result != VK_SUCCESS) { 87 ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d", 88 path.c_str(), result); 89 dlclose(dlhandle); 90 return; 91 } 92 VkLayerProperties* properties = static_cast<VkLayerProperties*>( 93 alloca(layer_count * sizeof(VkLayerProperties))); 94 result = enumerate_layer_properties(&layer_count, properties); 95 if (result != VK_SUCCESS) { 96 ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d", 97 path.c_str(), result); 98 dlclose(dlhandle); 99 return; 100 } 101 102 size_t library_idx = g_layer_libraries.size(); 103 g_layers.reserve(g_layers.size() + layer_count); 104 for (size_t i = 0; i < layer_count; i++) { 105 Layer layer; 106 layer.properties = properties[i]; 107 layer.library_idx = library_idx; 108 109 uint32_t count; 110 result = enumerate_extension_properties(properties[i].layerName, &count, 111 nullptr); 112 if (result != VK_SUCCESS) { 113 ALOGW( 114 "vkEnumerateInstanceExtensionProperties(%s) failed for library " 115 "'%s': %d", 116 properties[i].layerName, path.c_str(), result); 117 g_layers.resize(g_layers.size() - (i + 1)); 118 dlclose(dlhandle); 119 return; 120 } 121 layer.extensions.resize(count); 122 result = enumerate_extension_properties(properties[i].layerName, &count, 123 layer.extensions.data()); 124 if (result != VK_SUCCESS) { 125 ALOGW( 126 "vkEnumerateInstanceExtensionProperties(%s) failed for library " 127 "'%s': %d", 128 properties[i].layerName, path.c_str(), result); 129 g_layers.resize(g_layers.size() - (i + 1)); 130 dlclose(dlhandle); 131 return; 132 } 133 134 g_layers.push_back(layer); 135 ALOGV("found layer '%s'", properties[i].layerName); 136 } 137 138 dlclose(dlhandle); 139 140 g_layer_libraries.push_back(LayerLibrary{path, nullptr, 0}); 141} 142 143void DiscoverLayersInDirectory(const std::string& dir_path) { 144 ALOGV("looking for layers in '%s'", dir_path.c_str()); 145 146 DIR* directory = opendir(dir_path.c_str()); 147 if (!directory) { 148 int err = errno; 149 ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)", 150 dir_path.c_str(), strerror(err), err); 151 return; 152 } 153 154 std::string path; 155 path.reserve(dir_path.size() + 20); 156 path.append(dir_path); 157 path.append("/"); 158 159 struct dirent* entry; 160 while ((entry = readdir(directory))) { 161 size_t libname_len = strlen(entry->d_name); 162 if (strncmp(entry->d_name, "libVkLayer", 10) != 0 || 163 strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0) 164 continue; 165 path.append(entry->d_name); 166 AddLayerLibrary(path); 167 path.resize(dir_path.size() + 1); 168 } 169 170 closedir(directory); 171} 172 173void* GetLayerGetProcAddr(const Layer& layer, 174 const char* gpa_name, 175 size_t gpa_name_len) { 176 const LayerLibrary& library = g_layer_libraries[layer.library_idx]; 177 void* gpa; 178 size_t layer_name_len = std::max(2u, strlen(layer.properties.layerName)); 179 char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); 180 strcpy(name, layer.properties.layerName); 181 strcpy(name + layer_name_len, gpa_name); 182 if (!(gpa = dlsym(library.dlhandle, name))) { 183 strcpy(name, "vk"); 184 strcpy(name + 2, gpa_name); 185 gpa = dlsym(library.dlhandle, name); 186 } 187 return gpa; 188} 189 190} // anonymous namespace 191 192namespace vulkan { 193 194void DiscoverLayers() { 195 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) 196 DiscoverLayersInDirectory("/data/local/debug/vulkan"); 197 if (!LoaderData::GetInstance().layer_path.empty()) 198 DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str()); 199} 200 201uint32_t EnumerateLayers(uint32_t count, VkLayerProperties* properties) { 202 uint32_t n = std::min(count, g_layers.size()); 203 for (uint32_t i = 0; i < n; i++) { 204 properties[i] = g_layers[i].properties; 205 } 206 return g_layers.size(); 207} 208 209void GetLayerExtensions(const char* name, 210 const VkExtensionProperties** properties, 211 uint32_t* count) { 212 for (const auto& layer : g_layers) { 213 if (strcmp(name, layer.properties.layerName) != 0) 214 continue; 215 *properties = layer.extensions.data(); 216 *count = layer.extensions.size(); 217 } 218} 219 220LayerRef GetLayerRef(const char* name) { 221 for (uint32_t id = 0; id < g_layers.size(); id++) { 222 if (strcmp(name, g_layers[id].properties.layerName) != 0) { 223 LayerLibrary& library = g_layer_libraries[g_layers[id].library_idx]; 224 std::lock_guard<std::mutex> lock(g_library_mutex); 225 if (library.refcount++ == 0) { 226 library.dlhandle = 227 dlopen(library.path.c_str(), RTLD_NOW | RTLD_LOCAL); 228 if (!library.dlhandle) { 229 ALOGE("failed to load layer library '%s': %s", 230 library.path.c_str(), dlerror()); 231 library.refcount = 0; 232 return LayerRef(nullptr); 233 } 234 } 235 return LayerRef(&g_layers[id]); 236 } 237 } 238 return LayerRef(nullptr); 239} 240 241LayerRef::LayerRef(Layer* layer) : layer_(layer) {} 242 243LayerRef::~LayerRef() { 244 if (layer_) { 245 LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 246 std::lock_guard<std::mutex> lock(g_library_mutex); 247 if (--library.refcount == 0) { 248 dlclose(library.dlhandle); 249 library.dlhandle = nullptr; 250 } 251 } 252} 253 254LayerRef::LayerRef(LayerRef&& other) : layer_(std::move(other.layer_)) {} 255 256PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 257 return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 258 GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 259 : nullptr; 260} 261 262PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 263 return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 264 GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 265 : nullptr; 266} 267 268} // namespace vulkan 269