1/* 2 * Copyright (c) 2021 The Khronos Group Inc. 3 * Copyright (c) 2021 Valve Corporation 4 * Copyright (c) 2021 LunarG, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and/or associated documentation files (the "Materials"), to 8 * deal in the Materials without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Materials, and to permit persons to whom the Materials are 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice(s) and this permission notice shall be included in 14 * all copies or substantial portions of the Materials. 15 * 16 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 * 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 23 * USE OR OTHER DEALINGS IN THE MATERIALS. 24 * 25 * Author: Charles Giessen <charles@lunarg.com> 26 */ 27 28#include "shim.h" 29 30#include <random> 31 32void PlatformShim::redirect_all_paths(fs::path const& path) { 33 redirect_category(path, ManifestCategory::implicit_layer); 34 redirect_category(path, ManifestCategory::explicit_layer); 35 redirect_category(path, ManifestCategory::icd); 36} 37 38std::vector<std::string> parse_env_var_list(std::string const& var) { 39 std::vector<std::string> items; 40 size_t start = 0; 41 size_t len = 0; 42 for (size_t i = 0; i < var.size(); i++) { 43#if defined(WIN32) 44 if (var[i] == ';') { 45#elif COMMON_UNIX_PLATFORMS 46 if (var[i] == ':') { 47#endif 48 if (len != 0) { 49 // only push back non empty strings 50 items.push_back(var.substr(start, len)); 51 } 52 start = i + 1; 53 len = 0; 54 } else { 55 len++; 56 } 57 } 58 items.push_back(var.substr(start, len)); 59 60 return items; 61} 62 63std::vector<std::string> get_folder_contents(std::vector<fs::FolderManager>* folders, std::string folder_name) noexcept { 64 for (auto& folder : *folders) { 65 if (folder.location() == folder_name) { 66 return folder.get_files(); 67 } 68 } 69 return {}; 70} 71 72#if defined(WIN32) 73 74D3DKMT_Adapter& D3DKMT_Adapter::add_driver_manifest_path(fs::path const& src) { return add_path(src, driver_paths); } 75D3DKMT_Adapter& D3DKMT_Adapter::add_implicit_layer_manifest_path(fs::path const& src) { 76 return add_path(src, implicit_layer_paths); 77} 78D3DKMT_Adapter& D3DKMT_Adapter::add_explicit_layer_manifest_path(fs::path const& src) { 79 return add_path(src, explicit_layer_paths); 80} 81 82D3DKMT_Adapter& D3DKMT_Adapter::add_path(fs::path src, std::vector<std::wstring>& dest) { 83 std::wstring dest_path; 84 dest_path.resize(src.size()); 85 MultiByteToWideChar(CP_UTF8, 0, src.c_str(), static_cast<int>(src.size()), &dest_path[0], static_cast<int>(dest_path.size())); 86 dest.push_back(dest_path); 87 return *this; 88} 89 90std::string category_path_name(ManifestCategory category) { 91 if (category == ManifestCategory::implicit_layer) return "ImplicitLayers"; 92 if (category == ManifestCategory::explicit_layer) 93 return "ExplicitLayers"; 94 else 95 return "Drivers"; 96} 97 98void PlatformShim::reset() { 99 hkey_current_user_explicit_layers.clear(); 100 hkey_current_user_implicit_layers.clear(); 101 hkey_local_machine_explicit_layers.clear(); 102 hkey_local_machine_implicit_layers.clear(); 103 hkey_local_machine_drivers.clear(); 104 hkey_local_machine_settings.clear(); 105 hkey_current_user_settings.clear(); 106} 107 108void PlatformShim::set_fake_path([[maybe_unused]] ManifestCategory category, [[maybe_unused]] fs::path const& path) {} 109void PlatformShim::add_known_path([[maybe_unused]] fs::path const& path) {} 110 111void PlatformShim::add_manifest(ManifestCategory category, fs::path const& path) { 112 if (category == ManifestCategory::settings) { 113 hkey_local_machine_settings.emplace_back(path.str()); 114 } else if (category == ManifestCategory::implicit_layer) { 115 hkey_local_machine_implicit_layers.emplace_back(path.str()); 116 } else if (category == ManifestCategory::explicit_layer) { 117 hkey_local_machine_explicit_layers.emplace_back(path.str()); 118 } else { 119 hkey_local_machine_drivers.emplace_back(path.str()); 120 } 121} 122 123void PlatformShim::add_unsecured_manifest(ManifestCategory category, fs::path const& path) { 124 if (category == ManifestCategory::settings) { 125 hkey_current_user_settings.emplace_back(path.str()); 126 } else if (category == ManifestCategory::implicit_layer) { 127 hkey_current_user_implicit_layers.emplace_back(path.str()); 128 } else if (category == ManifestCategory::explicit_layer) { 129 hkey_current_user_explicit_layers.emplace_back(path.str()); 130 } 131} 132 133void PlatformShim::add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 desc1) { 134 uint32_t next_index = static_cast<uint32_t>(dxgi_adapters.size()); 135 dxgi_adapters.emplace(next_index, DXGIAdapter{gpu_preference, desc1, next_index}); 136} 137 138void PlatformShim::add_d3dkmt_adapter(D3DKMT_Adapter const& adapter) { d3dkmt_adapters.push_back(adapter); } 139 140void PlatformShim::set_app_package_path(fs::path const& path) { 141 app_package_path.resize(path.size()); 142 MultiByteToWideChar(CP_UTF8, 0, path.c_str(), -1, &app_package_path[0], static_cast<int>(app_package_path.size())); 143} 144 145// TODO: 146void PlatformShim::add_CM_Device_ID([[maybe_unused]] std::wstring const& id, [[maybe_unused]] fs::path const& icd_path, 147 [[maybe_unused]] fs::path const& layer_path) { 148 // // append a null byte as separator if there is already id's in the list 149 // if (CM_device_ID_list.size() != 0) { 150 // CM_device_ID_list += L'\0'; // I'm sure this wont cause issues with std::string down the line... /s 151 // } 152 // CM_device_ID_list += id; 153 // std::string id_str(id.length(), '\0'); 154 // size_t size_written{}; 155 // wcstombs_s(&size_written, &id_str[0], id_str.length(), id.c_str(), id.length()); 156 157 // std::string device_path = std::string(pnp_registry_path) + "\\" + id_str; 158 // CM_device_ID_registry_keys.push_back(device_path.c_str()); 159 // add_key_value_string(id_key, "VulkanDriverName", icd_path.c_str()); 160 // add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str()); 161 // // TODO: decide how to handle 32 bit 162 // // add_key_value_string(id_key, "VulkanDriverNameWoW", icd_path.c_str()); 163 // // add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str()); 164} 165 166void PlatformShim::redirect_category(fs::path const&, ManifestCategory) {} 167 168#elif COMMON_UNIX_PLATFORMS 169 170#include <dirent.h> 171#include <unistd.h> 172 173std::string category_path_name(ManifestCategory category) { 174 if (category == ManifestCategory::settings) return "settings.d"; 175 if (category == ManifestCategory::implicit_layer) return "implicit_layer.d"; 176 if (category == ManifestCategory::explicit_layer) 177 return "explicit_layer.d"; 178 else 179 return "icd.d"; 180} 181 182void PlatformShim::reset() { redirection_map.clear(); } 183 184bool PlatformShim::is_fake_path(fs::path const& path) { return redirection_map.count(path.str()) > 0; } 185fs::path const& PlatformShim::get_real_path_from_fake_path(fs::path const& path) { return redirection_map.at(path.str()); } 186void PlatformShim::redirect_path(fs::path const& path, fs::path const& new_path) { redirection_map[path.str()] = new_path; } 187void PlatformShim::remove_redirect(fs::path const& path) { redirection_map.erase(path.str()); } 188 189bool PlatformShim::is_known_path(fs::path const& path) { return known_path_set.count(path.str()) > 0; } 190void PlatformShim::add_known_path(fs::path const& path) { known_path_set.insert(path.str()); } 191void PlatformShim::remove_known_path(fs::path const& path) { known_path_set.erase(path.str()); } 192 193void PlatformShim::add_manifest([[maybe_unused]] ManifestCategory category, [[maybe_unused]] fs::path const& path) {} 194void PlatformShim::add_unsecured_manifest([[maybe_unused]] ManifestCategory category, [[maybe_unused]] fs::path const& path) {} 195 196void parse_and_add_env_var_override(std::vector<std::string>& paths, std::string env_var_contents) { 197 auto parsed_paths = parse_env_var_list(env_var_contents); 198 paths.insert(paths.end(), parsed_paths.begin(), parsed_paths.end()); 199} 200 201void PlatformShim::redirect_category(fs::path const& new_path, ManifestCategory category) { 202 std::vector<std::string> paths; 203 auto home = fs::path(get_env_var("HOME")); 204 if (category == ManifestCategory::settings) { 205 redirect_path(home / ".local/share/vulkan" / category_path_name(category), new_path); 206 return; 207 } 208 209 if (home.size() != 0) { 210 paths.push_back((home / ".config").str()); 211 paths.push_back((home / ".local/share").str()); 212 } 213 // Don't report errors on apple - these env-vars are not suppose to be defined 214 bool report_errors = true; 215#if defined(__APPLE__) 216 report_errors = false; 217#endif 218 parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_HOME", report_errors)); 219 if (category == ManifestCategory::explicit_layer) { 220 parse_and_add_env_var_override(paths, get_env_var("VK_LAYER_PATH", false)); // don't report failure 221 } 222 parse_and_add_env_var_override(paths, FALLBACK_DATA_DIRS); 223 parse_and_add_env_var_override(paths, FALLBACK_CONFIG_DIRS); 224 225 auto sys_conf_dir = std::string(SYSCONFDIR); 226 if (!sys_conf_dir.empty()) { 227 paths.push_back(sys_conf_dir); 228 } 229#if defined(EXTRASYSCONFDIR) 230 // EXTRASYSCONFDIR default is /etc, if SYSCONFDIR wasn't defined, it will have /etc put 231 // as its default. Don't want to double add it 232 auto extra_sys_conf_dir = std::string(EXTRASYSCONFDIR); 233 if (!extra_sys_conf_dir.empty() && sys_conf_dir != extra_sys_conf_dir) { 234 paths.push_back(extra_sys_conf_dir); 235 } 236#endif 237 238 for (auto& path : paths) { 239 if (!path.empty()) { 240 redirect_path(fs::path(path) / "vulkan" / category_path_name(category), new_path); 241 } 242 } 243} 244 245void PlatformShim::set_fake_path(ManifestCategory category, fs::path const& path) { 246 // use /etc as the 'redirection path' by default since its always searched 247 redirect_path(fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category), path); 248} 249 250void PlatformShim::redirect_dlopen_name(fs::path const& filename, fs::path const& actual_path) { 251 dlopen_redirection_map[filename.str()] = actual_path; 252} 253 254bool PlatformShim::is_dlopen_redirect_name(fs::path const& filename) { return dlopen_redirection_map.count(filename.str()) == 1; } 255 256fs::path PlatformShim::query_default_redirect_path(ManifestCategory category) { 257 return fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category); 258} 259#endif 260