layers_extensions.cpp revision dab25658fb17ec76569b8e91dfed801855027f08
180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall/* 280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * Copyright 2016 The Android Open Source Project 380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * 480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * Licensed under the Apache License, Version 2.0 (the "License"); 580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * you may not use this file except in compliance with the License. 680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * You may obtain a copy of the License at 780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * 880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * http://www.apache.org/licenses/LICENSE-2.0 980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * 1080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * Unless required by applicable law or agreed to in writing, software 1180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * distributed under the License is distributed on an "AS IS" BASIS, 1280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * See the License for the specific language governing permissions and 1480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall * limitations under the License. 1580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall */ 1680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 17d0b7cb566288a4f6646e356a17188b7922ba5740Michael Lentine// #define LOG_NDEBUG 0 18d0b7cb566288a4f6646e356a17188b7922ba5740Michael Lentine 19c96880f2cd1d34ffb9e3d10d80f0a3ddcc5579a8Chia-I Wu#include "layers_extensions.h" 2080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <alloca.h> 2180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <dirent.h> 2280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <dlfcn.h> 2380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <mutex> 2480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <sys/prctl.h> 2580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <string> 2680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <string.h> 2780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <vector> 2880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <log/log.h> 2980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall#include <vulkan/vulkan_loader_data.h> 3080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 31b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and 32b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall// not a good long-term solution. Having a hard-coded enum of extensions is 33b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall// bad, of course. Representing sets of extensions (requested, supported, etc.) 34b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall// as a bitset isn't necessarily bad, if the mapping from extension to bit were 35b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall// dynamic. Need to rethink this completely when there's a little more time. 36b147127b06c1ce6443839e8102d1ed2631a57b07Jesse Hall 37aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// TODO(jessehall): This file currently builds up global data structures as it 38aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// loads, and never cleans them up. This means we're doing heap allocations 39aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// without going through an app-provided allocator, but worse, we'll leak those 40aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// allocations if the loader is unloaded. 41aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// 42aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// We should allocate "enough" BSS space, and suballocate from there. Will 43aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// probably want to intern strings, etc., and will need some custom/manual data 44aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall// structures. 45aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 4680523e2e39c29b06ab40573468dde43a9867f487Jesse Hallnamespace vulkan { 47c96880f2cd1d34ffb9e3d10d80f0a3ddcc5579a8Chia-I Wunamespace api { 48c96880f2cd1d34ffb9e3d10d80f0a3ddcc5579a8Chia-I Wu 4980523e2e39c29b06ab40573468dde43a9867f487Jesse Hallstruct Layer { 5080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall VkLayerProperties properties; 5180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall size_t library_idx; 52bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu 5325700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu // true if the layer intercepts vkCreateDevice and device commands 54bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu bool is_global; 55bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu 56bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu std::vector<VkExtensionProperties> instance_extensions; 57bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu std::vector<VkExtensionProperties> device_extensions; 5880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall}; 5980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 6080523e2e39c29b06ab40573468dde43a9867f487Jesse Hallnamespace { 6180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 626693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wuclass LayerLibrary { 636693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu public: 646693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu LayerLibrary(const std::string& path) 656693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu : path_(path), dlhandle_(nullptr), refcount_(0) {} 66743495943b1a0b6d81ac70df524f67041f116ba6Chia-I Wu 6750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu LayerLibrary(LayerLibrary&& other) 686693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu : path_(std::move(other.path_)), 696693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlhandle_(other.dlhandle_), 706693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu refcount_(other.refcount_) { 716693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu other.dlhandle_ = nullptr; 726693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu other.refcount_ = 0; 7350174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu } 7450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 7550174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu LayerLibrary(const LayerLibrary&) = delete; 7650174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu LayerLibrary& operator=(const LayerLibrary&) = delete; 7750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 78a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu // these are thread-safe 79fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu bool Open(); 80d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wu void Close(); 81fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu 8250174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu bool EnumerateLayers(size_t library_idx, 83bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu std::vector<Layer>& instance_layers) const; 8450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 85ba113275287a2293136d8737bf364651ea0b576dChia-I Wu void* GetGPA(const Layer& layer, 86ba113275287a2293136d8737bf364651ea0b576dChia-I Wu const char* gpa_name, 87ba113275287a2293136d8737bf364651ea0b576dChia-I Wu size_t gpa_name_len) const; 88ba113275287a2293136d8737bf364651ea0b576dChia-I Wu 896693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu private: 906693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu const std::string path_; 91a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu 92a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu std::mutex mutex_; 936693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu void* dlhandle_; 946693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu size_t refcount_; 9580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall}; 96743495943b1a0b6d81ac70df524f67041f116ba6Chia-I Wu 97fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wubool LayerLibrary::Open() { 98a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu std::lock_guard<std::mutex> lock(mutex_); 99a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu 1006693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu if (refcount_++ == 0) { 1016693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL); 1026693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu ALOGV("Opening library %s", path_.c_str()); 1036693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu if (!dlhandle_) { 1046693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu ALOGE("failed to load layer library '%s': %s", path_.c_str(), 105fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu dlerror()); 1066693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu refcount_ = 0; 107fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu return false; 108fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu } 109fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu } 1106693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu ALOGV("Refcount on activate is %zu", refcount_); 111fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu return true; 112fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu} 113fd0389fb67298e530142566e7a5f6fb16741cabaChia-I Wu 114d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wuvoid LayerLibrary::Close() { 115a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu std::lock_guard<std::mutex> lock(mutex_); 116a6229749aeef225803c6a5411be9e8a40637454dChia-I Wu 1176693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu if (--refcount_ == 0) { 1186693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu ALOGV("Closing library %s", path_.c_str()); 1196693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlclose(dlhandle_); 1206693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlhandle_ = nullptr; 121d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wu } 1226693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu ALOGV("Refcount on destruction is %zu", refcount_); 123d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wu} 124d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wu 12550174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wubool LayerLibrary::EnumerateLayers(size_t library_idx, 126bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu std::vector<Layer>& instance_layers) const { 127aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers = 12880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>( 1296693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlsym(dlhandle_, "vkEnumerateInstanceLayerProperties")); 130aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions = 13180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>( 1326693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties")); 1335f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu if (!enumerate_instance_layers || !enumerate_instance_extensions) { 1345f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu ALOGV("layer library '%s' misses some instance enumeraion functions", 1355f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu path_.c_str()); 1365f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu return false; 1375f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu } 1385f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu 1395f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu // device functions are optional 140aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers = 141aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>( 1426693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlsym(dlhandle_, "vkEnumerateDeviceLayerProperties")); 143aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions = 144aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>( 1456693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu dlsym(dlhandle_, "vkEnumerateDeviceExtensionProperties")); 14680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 1475f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu // get layer counts 148aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall uint32_t num_instance_layers = 0; 149aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall uint32_t num_device_layers = 0; 1505f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu VkResult result = enumerate_instance_layers(&num_instance_layers, nullptr); 1515f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu if (result != VK_SUCCESS || !num_instance_layers) { 152aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (result != VK_SUCCESS) { 153aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall ALOGW( 154aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "vkEnumerateInstanceLayerProperties failed for library '%s': " 155aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "%d", 1566693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu path_.c_str(), result); 157aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 1585f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu return false; 15980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 160aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (enumerate_device_layers) { 161aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 162aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall nullptr); 163aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (result != VK_SUCCESS) { 164aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall ALOGW( 165aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 1666693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu path_.c_str(), result); 16750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return false; 168aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 16980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 1705f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu 1715f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu // get layer properties 172aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca( 173aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); 1745f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu result = enumerate_instance_layers(&num_instance_layers, properties); 1755f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu if (result != VK_SUCCESS) { 1765f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu ALOGW("vkEnumerateInstanceLayerProperties failed for library '%s': %d", 1775f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu path_.c_str(), result); 1785f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu return false; 179aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 180aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (num_device_layers > 0) { 181aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, 182aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall properties + num_instance_layers); 18380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall if (result != VK_SUCCESS) { 18480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall ALOGW( 185aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "vkEnumerateDeviceLayerProperties failed for library '%s': %d", 1866693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu path_.c_str(), result); 18750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return false; 18880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 189aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 190aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 191bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu // append layers to instance_layers 19250174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu size_t prev_num_instance_layers = instance_layers.size(); 19350174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu instance_layers.reserve(prev_num_instance_layers + num_instance_layers); 194aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall for (size_t i = 0; i < num_instance_layers; i++) { 195aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall const VkLayerProperties& props = properties[i]; 196aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 197aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall Layer layer; 198aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall layer.properties = props; 199aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall layer.library_idx = library_idx; 200bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu layer.is_global = false; 201aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 2025f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu uint32_t count = 0; 2035f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu result = 2045f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu enumerate_instance_extensions(props.layerName, &count, nullptr); 2055f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu if (result != VK_SUCCESS) { 2065f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu ALOGW( 2075f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu "vkEnumerateInstanceExtensionProperties(%s) failed for library " 2085f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu "'%s': %d", 2095f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu props.layerName, path_.c_str(), result); 2105f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu instance_layers.resize(prev_num_instance_layers); 2115f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu return false; 2125f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu } 213bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu layer.instance_extensions.resize(count); 214bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu result = enumerate_instance_extensions( 215bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu props.layerName, &count, layer.instance_extensions.data()); 2165f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu if (result != VK_SUCCESS) { 2175f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu ALOGW( 2185f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu "vkEnumerateInstanceExtensionProperties(%s) failed for library " 2195f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu "'%s': %d", 2205f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu props.layerName, path_.c_str(), result); 2215f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu instance_layers.resize(prev_num_instance_layers); 2225f093bf18120a5cbf18d0f3e255b2178f524e438Chia-I Wu return false; 223aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 22480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 225279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu for (size_t j = 0; j < num_device_layers; j++) { 226279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu const auto& dev_props = properties[num_instance_layers + j]; 227279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu if (memcmp(&props, &dev_props, sizeof(props)) == 0) { 228bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu layer.is_global = true; 229279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu break; 230279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu } 231279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu } 232279ccc0048d5bc7105af02538e33946814c68dc7Chia-I Wu 233bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu if (layer.is_global && enumerate_device_extensions) { 234aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall result = enumerate_device_extensions( 235aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall VK_NULL_HANDLE, props.layerName, &count, nullptr); 236aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (result != VK_SUCCESS) { 237aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall ALOGW( 238aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "vkEnumerateDeviceExtensionProperties(%s) failed for " 23950174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu "library '%s': %d", 2406693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu props.layerName, path_.c_str(), result); 24150174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu instance_layers.resize(prev_num_instance_layers); 24250174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return false; 243aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 244bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu layer.device_extensions.resize(count); 245bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu result = enumerate_device_extensions( 246bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu VK_NULL_HANDLE, props.layerName, &count, 247bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu layer.device_extensions.data()); 248aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (result != VK_SUCCESS) { 249aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall ALOGW( 250aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall "vkEnumerateDeviceExtensionProperties(%s) failed for " 25150174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu "library '%s': %d", 2526693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu props.layerName, path_.c_str(), result); 25350174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu instance_layers.resize(prev_num_instance_layers); 25450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return false; 255aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 256aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall } 257aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 258bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu instance_layers.push_back(layer); 259bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu ALOGV(" added %s layer '%s'", 260bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu (layer.is_global) ? "global" : "instance", props.layerName); 26180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 26280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 26350174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return true; 26450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu} 26550174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 266ba113275287a2293136d8737bf364651ea0b576dChia-I Wuvoid* LayerLibrary::GetGPA(const Layer& layer, 267ba113275287a2293136d8737bf364651ea0b576dChia-I Wu const char* gpa_name, 268ba113275287a2293136d8737bf364651ea0b576dChia-I Wu size_t gpa_name_len) const { 269ba113275287a2293136d8737bf364651ea0b576dChia-I Wu void* gpa; 270ba113275287a2293136d8737bf364651ea0b576dChia-I Wu size_t layer_name_len = 271ba113275287a2293136d8737bf364651ea0b576dChia-I Wu std::max(size_t{2}, strlen(layer.properties.layerName)); 272ba113275287a2293136d8737bf364651ea0b576dChia-I Wu char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); 273ba113275287a2293136d8737bf364651ea0b576dChia-I Wu strcpy(name, layer.properties.layerName); 274ba113275287a2293136d8737bf364651ea0b576dChia-I Wu strcpy(name + layer_name_len, gpa_name); 2756693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu if (!(gpa = dlsym(dlhandle_, name))) { 276ba113275287a2293136d8737bf364651ea0b576dChia-I Wu strcpy(name, "vk"); 277ba113275287a2293136d8737bf364651ea0b576dChia-I Wu strcpy(name + 2, gpa_name); 2786693f5cd2238fe08b382bf762e33b701312c7038Chia-I Wu gpa = dlsym(dlhandle_, name); 279ba113275287a2293136d8737bf364651ea0b576dChia-I Wu } 280ba113275287a2293136d8737bf364651ea0b576dChia-I Wu return gpa; 281ba113275287a2293136d8737bf364651ea0b576dChia-I Wu} 282ba113275287a2293136d8737bf364651ea0b576dChia-I Wu 28350174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wustd::vector<LayerLibrary> g_layer_libraries; 28450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wustd::vector<Layer> g_instance_layers; 28550174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 28650174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wuvoid AddLayerLibrary(const std::string& path) { 28750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu ALOGV("examining layer library '%s'", path.c_str()); 28850174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 28950174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu LayerLibrary library(path); 29050174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu if (!library.Open()) 29150174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return; 29250174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 293bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu if (!library.EnumerateLayers(g_layer_libraries.size(), g_instance_layers)) { 29450174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu library.Close(); 29550174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu return; 29650174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu } 29750174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu 29850174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu library.Close(); 29980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 30050174ee4ff2f6537c4aa4e8aa475f0dc8d910870Chia-I Wu g_layer_libraries.emplace_back(std::move(library)); 30180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 30280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 30380523e2e39c29b06ab40573468dde43a9867f487Jesse Hallvoid DiscoverLayersInDirectory(const std::string& dir_path) { 30480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall ALOGV("looking for layers in '%s'", dir_path.c_str()); 30580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 30680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall DIR* directory = opendir(dir_path.c_str()); 30780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall if (!directory) { 30880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall int err = errno; 30980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall ALOGV_IF(err != ENOENT, "failed to open layer directory '%s': %s (%d)", 31080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall dir_path.c_str(), strerror(err), err); 31180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall return; 31280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 31380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 31480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall std::string path; 31580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall path.reserve(dir_path.size() + 20); 31680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall path.append(dir_path); 31780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall path.append("/"); 31880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 31980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall struct dirent* entry; 32080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall while ((entry = readdir(directory))) { 32180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall size_t libname_len = strlen(entry->d_name); 322a7ac76df54c30e771ecfd05cdd2b52209af71470Jesse Hall if (strncmp(entry->d_name, "libVkLayer", 10) != 0 || 32380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall strncmp(entry->d_name + libname_len - 3, ".so", 3) != 0) 32480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall continue; 32580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall path.append(entry->d_name); 32680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall AddLayerLibrary(path); 32780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall path.resize(dir_path.size() + 1); 32880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 32980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 33080523e2e39c29b06ab40573468dde43a9867f487Jesse Hall closedir(directory); 33180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 33280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 333dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wuconst VkExtensionProperties* FindExtension( 334dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu const std::vector<VkExtensionProperties>& extensions, 335dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu const char* name) { 336dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu auto it = std::find_if(extensions.cbegin(), extensions.cend(), 337dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu [=](const VkExtensionProperties& ext) { 338dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu return (strcmp(ext.extensionName, name) == 0); 339dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu }); 340dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu return (it != extensions.cend()) ? &*it : nullptr; 341dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu} 342dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu 34380523e2e39c29b06ab40573468dde43a9867f487Jesse Hallvoid* GetLayerGetProcAddr(const Layer& layer, 34480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall const char* gpa_name, 34580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall size_t gpa_name_len) { 34680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall const LayerLibrary& library = g_layer_libraries[layer.library_idx]; 347ba113275287a2293136d8737bf364651ea0b576dChia-I Wu return library.GetGPA(layer, gpa_name, gpa_name_len); 34880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 34980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 350aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} // anonymous namespace 351aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 352aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hallvoid DiscoverLayers() { 353aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) 354aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall DiscoverLayersInDirectory("/data/local/debug/vulkan"); 355aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall if (!LoaderData::GetInstance().layer_path.empty()) 356aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall DiscoverLayersInDirectory(LoaderData::GetInstance().layer_path.c_str()); 357aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 358aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 35925700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wuuint32_t GetLayerCount() { 360bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu return static_cast<uint32_t>(g_instance_layers.size()); 361aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 362aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 36325700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wuconst Layer& GetLayer(uint32_t index) { 36425700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu return g_instance_layers[index]; 36525700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu} 366bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu 36704c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wuconst Layer* FindLayer(const char* name) { 36804c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu auto layer = 36904c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu std::find_if(g_instance_layers.cbegin(), g_instance_layers.cend(), 37004c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu [=](const Layer& entry) { 37104c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu return strcmp(entry.properties.layerName, name) == 0; 37204c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu }); 37304c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu return (layer != g_instance_layers.cend()) ? &*layer : nullptr; 37404c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu} 37504c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu 37625700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wuconst VkLayerProperties& GetLayerProperties(const Layer& layer) { 37725700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu return layer.properties; 37825700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu} 379bea09db9c2165f06771f3a3da423f4f85ac6347eChia-I Wu 38025700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wubool IsLayerGlobal(const Layer& layer) { 38125700b452535ce7ae838bfe832392b46ed555ed2Chia-I Wu return layer.is_global; 382aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 383aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 38404c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wuconst VkExtensionProperties* GetLayerInstanceExtensions(const Layer& layer, 38504c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu uint32_t& count) { 38604c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu count = static_cast<uint32_t>(layer.instance_extensions.size()); 38704c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu return layer.instance_extensions.data(); 388aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 389aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 39004c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wuconst VkExtensionProperties* GetLayerDeviceExtensions(const Layer& layer, 39104c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu uint32_t& count) { 39204c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu count = static_cast<uint32_t>(layer.device_extensions.size()); 39304c6551eb812a7efe38fa74e6ac67c17aab3df2dChia-I Wu return layer.device_extensions.data(); 394aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 395aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 396dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wuconst VkExtensionProperties* FindLayerInstanceExtension(const Layer& layer, 397dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu const char* name) { 398dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu return FindExtension(layer.instance_extensions, name); 399aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 400aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 401dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wuconst VkExtensionProperties* FindLayerDeviceExtension(const Layer& layer, 402dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu const char* name) { 403dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu return FindExtension(layer.device_extensions, name); 404dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu} 405dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu 406dab25658fb17ec76569b8e91dfed801855027f08Chia-I WuLayerRef GetLayerRef(const Layer& layer) { 407d6e6f51426c566cd67ed765e5c4b206a063aaa30Chia-I Wu LayerLibrary& library = g_layer_libraries[layer.library_idx]; 408dab25658fb17ec76569b8e91dfed801855027f08Chia-I Wu return LayerRef((library.Open()) ? &layer : nullptr); 409aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall} 410aa410941d29cba4a3a56e90cb3f0be3f03c76ceaJesse Hall 411dab25658fb17ec76569b8e91dfed801855027f08Chia-I WuLayerRef::LayerRef(const Layer* layer) : layer_(layer) {} 41280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 41380523e2e39c29b06ab40573468dde43a9867f487Jesse HallLayerRef::~LayerRef() { 41480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall if (layer_) { 41580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall LayerLibrary& library = g_layer_libraries[layer_->library_idx]; 416d91c74f917b603d8d1dec7d27da03e580919e0a6Chia-I Wu library.Close(); 41780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall } 41880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 41980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 420dab25658fb17ec76569b8e91dfed801855027f08Chia-I WuLayerRef::LayerRef(LayerRef&& other) : layer_(other.layer_) { 42154e6f086a6b373a0f496343451a76dde8aa86238Michael Lentine other.layer_ = nullptr; 42254e6f086a6b373a0f496343451a76dde8aa86238Michael Lentine} 42380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 42480523e2e39c29b06ab40573468dde43a9867f487Jesse HallPFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { 42580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( 42680523e2e39c29b06ab40573468dde43a9867f487Jesse Hall GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) 42780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall : nullptr; 42880523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 42980523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 43080523e2e39c29b06ab40573468dde43a9867f487Jesse HallPFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { 43180523e2e39c29b06ab40573468dde43a9867f487Jesse Hall return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( 43280523e2e39c29b06ab40573468dde43a9867f487Jesse Hall GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) 43380523e2e39c29b06ab40573468dde43a9867f487Jesse Hall : nullptr; 43480523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} 43580523e2e39c29b06ab40573468dde43a9867f487Jesse Hall 436c96880f2cd1d34ffb9e3d10d80f0a3ddcc5579a8Chia-I Wu} // namespace api 43780523e2e39c29b06ab40573468dde43a9867f487Jesse Hall} // namespace vulkan 438