• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "layers_extensions.h"
18 
19 #include "base/System.h"
20 #include "base/PathUtils.h"
21 
22 #include <alloca.h>
23 #include <dirent.h>
24 #include <dlfcn.h>
25 #include <string.h>
26 
27 #include <algorithm>
28 #include <memory>
29 #include <mutex>
30 #include <string>
31 #include <vector>
32 
33 #include <android/dlext.h>
34 #include <cutils/properties.h>
35 #include <log/log.h>
36 
37 using android::base::pj;
38 
39 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
40 // not a good long-term solution. Having a hard-coded enum of extensions is
41 // bad, of course. Representing sets of extensions (requested, supported, etc.)
42 // as a bitset isn't necessarily bad, if the mapping from extension to bit were
43 // dynamic. Need to rethink this completely when there's a little more time.
44 
45 // TODO(jessehall): This file currently builds up global data structures as it
46 // loads, and never cleans them up. This means we're doing heap allocations
47 // without going through an app-provided allocator, but worse, we'll leak those
48 // allocations if the loader is unloaded.
49 //
50 // We should allocate "enough" BSS space, and suballocate from there. Will
51 // probably want to intern strings, etc., and will need some custom/manual data
52 // structures.
53 
54 namespace vulkan {
55 namespace api {
56 
57 struct Layer {
58     VkLayerProperties properties;
59     size_t library_idx;
60 
61     // true if the layer intercepts vkCreateDevice and device commands
62     bool is_global;
63 
64     std::vector<VkExtensionProperties> instance_extensions;
65     std::vector<VkExtensionProperties> device_extensions;
66 };
67 
68 namespace {
69 
70 const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan";
71 
72 class LayerLibrary {
73    public:
LayerLibrary(const std::string & path,const std::string & filename)74     explicit LayerLibrary(const std::string& path,
75                           const std::string& filename)
76         : path_(path),
77           filename_(filename),
78           dlhandle_(nullptr),
79           native_bridge_(false),
80           refcount_(0) {}
81 
LayerLibrary(LayerLibrary && other)82     LayerLibrary(LayerLibrary&& other) noexcept
83         : path_(std::move(other.path_)),
84           filename_(std::move(other.filename_)),
85           dlhandle_(other.dlhandle_),
86           native_bridge_(other.native_bridge_),
87           refcount_(other.refcount_) {
88         other.dlhandle_ = nullptr;
89         other.refcount_ = 0;
90     }
91 
92     LayerLibrary(const LayerLibrary&) = delete;
93     LayerLibrary& operator=(const LayerLibrary&) = delete;
94 
95     // these are thread-safe
96     bool Open();
97     void Close();
98 
99     bool EnumerateLayers(size_t library_idx,
100                          std::vector<Layer>& instance_layers) const;
101 
102     void* GetGPA(const Layer& layer,
103                  const char* gpa_name,
104                  size_t gpa_name_len) const;
105 
GetFilename()106     const std::string GetFilename() { return filename_; }
107 
108    private:
109     // TODO(b/79940628): remove that adapter when we could use NativeBridgeGetTrampoline
110     // for native libraries.
111     template<typename Func = void*>
GetTrampoline(const char * name) const112     Func GetTrampoline(const char* name) const {
113         return reinterpret_cast<Func>(dlsym(dlhandle_, name));
114     }
115 
116     const std::string path_;
117 
118     // Track the filename alone so we can detect duplicates
119     const std::string filename_;
120 
121     std::mutex mutex_;
122     void* dlhandle_;
123     bool native_bridge_;
124     size_t refcount_;
125 };
126 
Open()127 bool LayerLibrary::Open() {
128     std::lock_guard<std::mutex> lock(mutex_);
129     if (refcount_++ == 0) {
130         ALOGV("opening layer library '%s'", path_.c_str());
131         dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
132         if (!dlhandle_) {
133             ALOGE("failed to load layer library '%s': %s", path_.c_str(),
134                   dlerror());
135             refcount_ = 0;
136             return false;
137         }
138     }
139     return true;
140 }
141 
Close()142 void LayerLibrary::Close() {
143     std::lock_guard<std::mutex> lock(mutex_);
144     if (--refcount_ == 0) {
145         ALOGV("closing layer library '%s'", path_.c_str());
146         std::string error_msg;
147         dlclose(dlhandle_);
148         dlhandle_ = nullptr;
149     }
150 }
151 
EnumerateLayers(size_t library_idx,std::vector<Layer> & instance_layers) const152 bool LayerLibrary::EnumerateLayers(size_t library_idx,
153                                    std::vector<Layer>& instance_layers) const {
154     PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
155         GetTrampoline<PFN_vkEnumerateInstanceLayerProperties>(
156             "vkEnumerateInstanceLayerProperties");
157     PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
158         GetTrampoline<PFN_vkEnumerateInstanceExtensionProperties>(
159             "vkEnumerateInstanceExtensionProperties");
160     if (!enumerate_instance_layers || !enumerate_instance_extensions) {
161         ALOGE("layer library '%s' missing some instance enumeration functions",
162               path_.c_str());
163         return false;
164     }
165 
166     // device functions are optional
167     PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
168         GetTrampoline<PFN_vkEnumerateDeviceLayerProperties>(
169             "vkEnumerateDeviceLayerProperties");
170     PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
171         GetTrampoline<PFN_vkEnumerateDeviceExtensionProperties>(
172             "vkEnumerateDeviceExtensionProperties");
173 
174     // get layer counts
175     uint32_t num_instance_layers = 0;
176     uint32_t num_device_layers = 0;
177     VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr);
178     if (result != VK_SUCCESS || !num_instance_layers) {
179         if (result != VK_SUCCESS) {
180             ALOGE(
181                 "vkEnumerateInstanceLayerProperties failed for library '%s': "
182                 "%d",
183                 path_.c_str(), result);
184         }
185         return false;
186     }
187     if (enumerate_device_layers) {
188         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
189                                          nullptr);
190         if (result != VK_SUCCESS) {
191             ALOGE(
192                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
193                 path_.c_str(), result);
194             return false;
195         }
196     }
197 
198     // get layer properties
199     VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
200         (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
201     result = enumerate_instance_layers(&num_instance_layers, properties);
202     if (result != VK_SUCCESS) {
203         ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
204               path_.c_str(), result);
205         return false;
206     }
207     if (num_device_layers > 0) {
208         result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
209                                          properties + num_instance_layers);
210         if (result != VK_SUCCESS) {
211             ALOGE(
212                 "vkEnumerateDeviceLayerProperties failed for library '%s': %d",
213                 path_.c_str(), result);
214             return false;
215         }
216     }
217 
218     // append layers to instance_layers
219     size_t prev_num_instance_layers = instance_layers.size();
220     instance_layers.reserve(prev_num_instance_layers + num_instance_layers);
221     for (size_t i = 0; i < num_instance_layers; i++) {
222         const VkLayerProperties& props = properties[i];
223 
224         Layer layer;
225         layer.properties = props;
226         layer.library_idx = library_idx;
227         layer.is_global = false;
228 
229         uint32_t count = 0;
230         result =
231             enumerate_instance_extensions(props.layerName, &count, nullptr);
232         if (result != VK_SUCCESS) {
233             ALOGE(
234                 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
235                 "library '%s': %d",
236                 props.layerName, path_.c_str(), result);
237             instance_layers.resize(prev_num_instance_layers);
238             return false;
239         }
240         layer.instance_extensions.resize(count);
241         result = enumerate_instance_extensions(
242             props.layerName, &count, layer.instance_extensions.data());
243         if (result != VK_SUCCESS) {
244             ALOGE(
245                 "vkEnumerateInstanceExtensionProperties(\"%s\") failed for "
246                 "library '%s': %d",
247                 props.layerName, path_.c_str(), result);
248             instance_layers.resize(prev_num_instance_layers);
249             return false;
250         }
251 
252         for (size_t j = 0; j < num_device_layers; j++) {
253             const auto& dev_props = properties[num_instance_layers + j];
254             if (memcmp(&props, &dev_props, sizeof(props)) == 0) {
255                 layer.is_global = true;
256                 break;
257             }
258         }
259 
260         if (layer.is_global && enumerate_device_extensions) {
261             result = enumerate_device_extensions(
262                 VK_NULL_HANDLE, props.layerName, &count, nullptr);
263             if (result != VK_SUCCESS) {
264                 ALOGE(
265                     "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
266                     "library '%s': %d",
267                     props.layerName, path_.c_str(), result);
268                 instance_layers.resize(prev_num_instance_layers);
269                 return false;
270             }
271             layer.device_extensions.resize(count);
272             result = enumerate_device_extensions(
273                 VK_NULL_HANDLE, props.layerName, &count,
274                 layer.device_extensions.data());
275             if (result != VK_SUCCESS) {
276                 ALOGE(
277                     "vkEnumerateDeviceExtensionProperties(\"%s\") failed for "
278                     "library '%s': %d",
279                     props.layerName, path_.c_str(), result);
280                 instance_layers.resize(prev_num_instance_layers);
281                 return false;
282             }
283         }
284 
285         instance_layers.push_back(layer);
286         ALOGD("added %s layer '%s' from library '%s'",
287               (layer.is_global) ? "global" : "instance", props.layerName,
288               path_.c_str());
289     }
290 
291     return true;
292 }
293 
GetGPA(const Layer & layer,const char * gpa_name,size_t gpa_name_len) const294 void* LayerLibrary::GetGPA(const Layer& layer,
295                            const char* gpa_name,
296                            size_t gpa_name_len) const {
297     void* gpa;
298     size_t layer_name_len =
299         std::max(size_t{2}, strlen(layer.properties.layerName));
300     char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
301     strcpy(name, layer.properties.layerName);
302     strcpy(name + layer_name_len, gpa_name);
303     if (!(gpa = GetTrampoline(name))) {
304         strcpy(name, "vk");
305         strcpy(name + 2, gpa_name);
306         gpa = GetTrampoline(name);
307     }
308     return gpa;
309 }
310 
311 // ----------------------------------------------------------------------------
312 
313 std::vector<LayerLibrary> g_layer_libraries;
314 std::vector<Layer> g_instance_layers;
315 
AddLayerLibrary(const std::string & path,const std::string & filename)316 void AddLayerLibrary(const std::string& path, const std::string& filename) {
317     LayerLibrary library(path + "/" + filename, filename);
318     if (!library.Open())
319         return;
320 
321     if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) {
322         library.Close();
323         return;
324     }
325 
326     library.Close();
327 
328     g_layer_libraries.emplace_back(std::move(library));
329 }
330 
331 template <typename Functor>
ForEachFileInDir(const std::string & dirname,Functor functor)332 void ForEachFileInDir(const std::string& dirname, Functor functor) {
333     auto dir_deleter = [](DIR* handle) { closedir(handle); };
334     std::unique_ptr<DIR, decltype(dir_deleter)> dir(opendir(dirname.c_str()),
335                                                     dir_deleter);
336     if (!dir) {
337         // It's normal for some search directories to not exist, especially
338         // /data/local/debug/vulkan.
339         int err = errno;
340         ALOGW_IF(err != ENOENT, "failed to open layer directory '%s': %s",
341                  dirname.c_str(), strerror(err));
342         return;
343     }
344     ALOGD("searching for layers in '%s'", dirname.c_str());
345     dirent* entry;
346     while ((entry = readdir(dir.get())) != nullptr)
347         functor(entry->d_name);
348 }
349 
350 template <typename Functor>
ForEachFileInPath(const std::string & path,Functor functor)351 void ForEachFileInPath(const std::string& path, Functor functor) {
352     size_t zip_pos = path.find("!/");
353     if (zip_pos == std::string::npos) {
354         ForEachFileInDir(path, functor);
355     }
356 }
357 
DiscoverLayersInPathList(const std::string & path)358 void DiscoverLayersInPathList(const std::string& path) {
359     ForEachFileInPath(path, [&](const std::string& filename) {
360         if (filename.find("libVkLayer") == 0) {
361             // Check to ensure we haven't seen this layer already
362             // Let the first instance of the shared object be enumerated
363             // We're searching for layers in following order:
364             // 1. system path
365             // 2. libraryPermittedPath (if enabled)
366             // 3. libraryPath
367 
368             bool duplicate = false;
369             for (auto& layer : g_layer_libraries) {
370                 if (layer.GetFilename() == filename) {
371                     ALOGV("Skipping duplicate layer %s in %s", filename.c_str(),
372                           path.c_str());
373                     duplicate = true;
374                 }
375             }
376 
377             if (!duplicate)
378                 AddLayerLibrary(path, filename);
379         }
380     });
381 }
382 
FindExtension(const std::vector<VkExtensionProperties> & extensions,const char * name)383 const VkExtensionProperties* FindExtension(
384     const std::vector<VkExtensionProperties>& extensions,
385     const char* name) {
386     auto it = std::find_if(extensions.cbegin(), extensions.cend(),
387                            [=](const VkExtensionProperties& ext) {
388                                return (strcmp(ext.extensionName, name) == 0);
389                            });
390     return (it != extensions.cend()) ? &*it : nullptr;
391 }
392 
GetLayerGetProcAddr(const Layer & layer,const char * gpa_name,size_t gpa_name_len)393 void* GetLayerGetProcAddr(const Layer& layer,
394                           const char* gpa_name,
395                           size_t gpa_name_len) {
396     const LayerLibrary& library = g_layer_libraries[layer.library_idx];
397     return library.GetGPA(layer, gpa_name, gpa_name_len);
398 }
399 
400 }  // anonymous namespace
401 
DiscoverLayers()402 void DiscoverLayers() {
403     auto layerDiscoveryPath =
404         pj({android::base::getProgramDirectory(), "lib64"});
405     DiscoverLayersInPathList(layerDiscoveryPath);
406     std::string vkSdkPath = android::base::getEnvironmentVariable("VULKAN_SDK");
407     if (vkSdkPath != "") {
408         DiscoverLayersInPathList(vkSdkPath);
409     }
410 }
411 
GetLayerCount()412 uint32_t GetLayerCount() {
413     return static_cast<uint32_t>(g_instance_layers.size());
414 }
415 
GetLayer(uint32_t index)416 const Layer& GetLayer(uint32_t index) {
417     return g_instance_layers[index];
418 }
419 
FindLayer(const char * name)420 const Layer* FindLayer(const char* name) {
421     auto layer =
422         std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(),
423                      [=](const Layer& entry) {
424                          return strcmp(entry.properties.layerName, name) == 0;
425                      });
426     return (layer != g_instance_layers.cend()) ? &*layer : nullptr;
427 }
428 
GetLayerProperties(const Layer & layer)429 const VkLayerProperties& GetLayerProperties(const Layer& layer) {
430     return layer.properties;
431 }
432 
IsLayerGlobal(const Layer & layer)433 bool IsLayerGlobal(const Layer& layer) {
434     return layer.is_global;
435 }
436 
GetLayerInstanceExtensions(const Layer & layer,uint32_t & count)437 const VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer,
438                                                         uint32_t& count) {
439     count = static_cast<uint32_t>(layer.instance_extensions.size());
440     return layer.instance_extensions.data();
441 }
442 
GetLayerDeviceExtensions(const Layer & layer,uint32_t & count)443 const VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer,
444                                                       uint32_t& count) {
445     count = static_cast<uint32_t>(layer.device_extensions.size());
446     return layer.device_extensions.data();
447 }
448 
FindLayerInstanceExtension(const Layer & layer,const char * name)449 const VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer,
450                                                         const char* name) {
451     return FindExtension(layer.instance_extensions, name);
452 }
453 
FindLayerDeviceExtension(const Layer & layer,const char * name)454 const VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer,
455                                                       const char* name) {
456     return FindExtension(layer.device_extensions, name);
457 }
458 
GetLayerRef(const Layer & layer)459 LayerRef GetLayerRef(const Layer& layer) {
460     LayerLibrary& library = g_layer_libraries[layer.library_idx];
461     return LayerRef((library.Open()) ? &layer : nullptr);
462 }
463 
LayerRef(const Layer * layer)464 LayerRef::LayerRef(const Layer* layer) : layer_(layer) {}
465 
~LayerRef()466 LayerRef::~LayerRef() {
467     if (layer_) {
468         LayerLibrary& library = g_layer_libraries[layer_->library_idx];
469         library.Close();
470     }
471 }
472 
LayerRef(LayerRef && other)473 LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
474     other.layer_ = nullptr;
475 }
476 
GetGetInstanceProcAddr() const477 PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
478     return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
479                         GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
480                   : nullptr;
481 }
482 
GetGetDeviceProcAddr() const483 PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
484     return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
485                         GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
486                   : nullptr;
487 }
488 
489 }  // namespace api
490 }  // namespace vulkan
491