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
redirect_all_paths(std::filesystem::path const & path)30 void PlatformShim::redirect_all_paths(std::filesystem::path const& path) {
31 redirect_category(path, ManifestCategory::implicit_layer);
32 redirect_category(path, ManifestCategory::explicit_layer);
33 redirect_category(path, ManifestCategory::icd);
34 }
35
parse_env_var_list(std::string const & var)36 std::vector<std::string> parse_env_var_list(std::string const& var) {
37 std::vector<std::string> items;
38 size_t start = 0;
39 size_t len = 0;
40 for (size_t i = 0; i < var.size(); i++) {
41 #if defined(WIN32)
42 if (var[i] == ';') {
43 #elif COMMON_UNIX_PLATFORMS
44 if (var[i] == ':') {
45 #endif
46 if (len != 0) {
47 // only push back non empty strings
48 items.push_back(var.substr(start, len));
49 }
50 start = i + 1;
51 len = 0;
52 } else {
53 len++;
54 }
55 }
56 items.push_back(var.substr(start, len));
57
58 return items;
59 }
60
61 std::vector<std::filesystem::path> get_folder_contents(std::vector<fs::FolderManager>* folders,
62 std::filesystem::path folder_name) noexcept {
63 for (auto& folder : *folders) {
64 if (folder.location() == folder_name) {
65 return folder.get_files();
66 }
67 }
68 return {};
69 }
70
71 #if defined(WIN32)
72
73 D3DKMT_Adapter& D3DKMT_Adapter::add_driver_manifest_path(std::filesystem::path const& src) { return add_path(src, driver_paths); }
74 D3DKMT_Adapter& D3DKMT_Adapter::add_implicit_layer_manifest_path(std::filesystem::path const& src) {
75 return add_path(src, implicit_layer_paths);
76 }
77 D3DKMT_Adapter& D3DKMT_Adapter::add_explicit_layer_manifest_path(std::filesystem::path const& src) {
78 return add_path(src, explicit_layer_paths);
79 }
80
81 D3DKMT_Adapter& D3DKMT_Adapter::add_path(std::filesystem::path src, std::vector<std::wstring>& dest) {
82 dest.push_back(src.native());
83 return *this;
84 }
85
86 std::string category_path_name(ManifestCategory category) {
87 if (category == ManifestCategory::implicit_layer) return "ImplicitLayers";
88 if (category == ManifestCategory::explicit_layer)
89 return "ExplicitLayers";
90 else
91 return "Drivers";
92 }
93
94 void PlatformShim::reset() {
95 hkey_current_user_explicit_layers.clear();
96 hkey_current_user_implicit_layers.clear();
97 hkey_local_machine_explicit_layers.clear();
98 hkey_local_machine_implicit_layers.clear();
99 hkey_local_machine_drivers.clear();
100 hkey_local_machine_settings.clear();
101 hkey_current_user_settings.clear();
102 }
103
104 void PlatformShim::set_fake_path([[maybe_unused]] ManifestCategory category, [[maybe_unused]] std::filesystem::path const& path) {}
105 void PlatformShim::add_known_path([[maybe_unused]] std::filesystem::path const& path) {}
106
107 void PlatformShim::add_manifest(ManifestCategory category, std::filesystem::path const& path) {
108 if (category == ManifestCategory::settings) {
109 hkey_local_machine_settings.emplace_back(path);
110 } else if (category == ManifestCategory::implicit_layer) {
111 hkey_local_machine_implicit_layers.emplace_back(path);
112 } else if (category == ManifestCategory::explicit_layer) {
113 hkey_local_machine_explicit_layers.emplace_back(path);
114 } else {
115 hkey_local_machine_drivers.emplace_back(path);
116 }
117 }
118
119 void PlatformShim::add_unsecured_manifest(ManifestCategory category, std::filesystem::path const& path) {
120 if (category == ManifestCategory::settings) {
121 hkey_current_user_settings.emplace_back(path);
122 } else if (category == ManifestCategory::implicit_layer) {
123 hkey_current_user_implicit_layers.emplace_back(path);
124 } else if (category == ManifestCategory::explicit_layer) {
125 hkey_current_user_explicit_layers.emplace_back(path);
126 }
127 }
128
129 void PlatformShim::add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 desc1) {
130 uint32_t next_index = static_cast<uint32_t>(dxgi_adapters.size());
131 dxgi_adapters.emplace(next_index, DXGIAdapter{gpu_preference, desc1, next_index});
132 }
133
134 void PlatformShim::add_d3dkmt_adapter(D3DKMT_Adapter const& adapter) { d3dkmt_adapters.push_back(adapter); }
135
136 void PlatformShim::set_app_package_path(std::filesystem::path const& path) { app_package_path = path; }
137
138 // TODO:
139 void PlatformShim::add_CM_Device_ID([[maybe_unused]] std::wstring const& id, [[maybe_unused]] std::filesystem::path const& icd_path,
140 [[maybe_unused]] std::filesystem::path const& layer_path) {
141 // // append a null byte as separator if there is already id's in the list
142 // if (CM_device_ID_list.size() != 0) {
143 // CM_device_ID_list += L'\0'; // I'm sure this wont cause issues with std::string down the line... /s
144 // }
145 // CM_device_ID_list += id;
146 // std::string id_str(id.length(), '\0');
147 // size_t size_written{};
148 // wcstombs_s(&size_written, &id_str[0], id_str.length(), id.c_str(), id.length());
149
150 // std::string device_path = std::string(pnp_registry_path) + "\\" + id_str;
151 // CM_device_ID_registry_keys.push_back(device_path.c_str());
152 // add_key_value_string(id_key, "VulkanDriverName", icd_path.c_str());
153 // add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str());
154 // // TODO: decide how to handle 32 bit
155 // // add_key_value_string(id_key, "VulkanDriverNameWoW", icd_path.c_str());
156 // // add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str());
157 }
158
159 void PlatformShim::redirect_category(std::filesystem::path const&, ManifestCategory) {}
160
161 #elif COMMON_UNIX_PLATFORMS
162
163 #include <dirent.h>
164 #include <unistd.h>
165
166 std::string category_path_name(ManifestCategory category) {
167 if (category == ManifestCategory::settings) return "settings.d";
168 if (category == ManifestCategory::implicit_layer) return "implicit_layer.d";
169 if (category == ManifestCategory::explicit_layer)
170 return "explicit_layer.d";
171 else
172 return "icd.d";
173 }
174
175 void PlatformShim::reset() { redirection_map.clear(); }
176
177 bool PlatformShim::is_fake_path(std::filesystem::path const& path) { return redirection_map.count(path) > 0; }
178 std::filesystem::path const& PlatformShim::get_real_path_from_fake_path(std::filesystem::path const& path) {
179 return redirection_map.at(path);
180 }
181 void PlatformShim::redirect_path(std::filesystem::path const& path, std::filesystem::path const& new_path) {
182 redirection_map[path] = new_path;
183 }
184 void PlatformShim::remove_redirect(std::filesystem::path const& path) { redirection_map.erase(path); }
185
186 bool PlatformShim::is_known_path(std::filesystem::path const& path) { return known_path_set.count(path) > 0; }
187 void PlatformShim::add_known_path(std::filesystem::path const& path) { known_path_set.insert(path); }
188 void PlatformShim::remove_known_path(std::filesystem::path const& path) { known_path_set.erase(path); }
189
190 void PlatformShim::add_manifest([[maybe_unused]] ManifestCategory category, [[maybe_unused]] std::filesystem::path const& path) {}
191 void PlatformShim::add_unsecured_manifest([[maybe_unused]] ManifestCategory category,
192 [[maybe_unused]] std::filesystem::path const& path) {}
193
194 void parse_and_add_env_var_override(std::vector<std::string>& paths, std::string env_var_contents) {
195 auto parsed_paths = parse_env_var_list(env_var_contents);
196 paths.insert(paths.end(), parsed_paths.begin(), parsed_paths.end());
197 }
198
199 void PlatformShim::redirect_category(std::filesystem::path const& new_path, ManifestCategory category) {
200 std::vector<std::string> paths;
201 auto home = std::filesystem::path(get_env_var("HOME"));
202 if (category == ManifestCategory::settings) {
203 redirect_path(home / ".local/share/vulkan" / category_path_name(category), new_path);
204 return;
205 }
206
207 if (!home.empty()) {
208 paths.push_back((home / ".config"));
209 paths.push_back((home / ".local/share"));
210 }
211 // Don't report errors on apple - these env-vars are not suppose to be defined
212 bool report_errors = true;
213 #if defined(__APPLE__)
214 report_errors = false;
215 #endif
216 parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_HOME", report_errors));
217 if (category == ManifestCategory::explicit_layer) {
218 parse_and_add_env_var_override(paths, get_env_var("VK_LAYER_PATH", false)); // don't report failure
219 }
220 if (category == ManifestCategory::implicit_layer) {
221 parse_and_add_env_var_override(paths, get_env_var("VK_IMPLICIT_LAYER_PATH", false)); // don't report failure
222 }
223 parse_and_add_env_var_override(paths, FALLBACK_DATA_DIRS);
224 parse_and_add_env_var_override(paths, FALLBACK_CONFIG_DIRS);
225
226 auto sys_conf_dir = std::string(SYSCONFDIR);
227 if (!sys_conf_dir.empty()) {
228 paths.push_back(sys_conf_dir);
229 }
230 #if defined(EXTRASYSCONFDIR)
231 // EXTRASYSCONFDIR default is /etc, if SYSCONFDIR wasn't defined, it will have /etc put
232 // as its default. Don't want to double add it
233 auto extra_sys_conf_dir = std::string(EXTRASYSCONFDIR);
234 if (!extra_sys_conf_dir.empty() && sys_conf_dir != extra_sys_conf_dir) {
235 paths.push_back(extra_sys_conf_dir);
236 }
237 #endif
238
239 for (auto& path : paths) {
240 if (!path.empty()) {
241 redirect_path(std::filesystem::path(path) / "vulkan" / category_path_name(category), new_path);
242 }
243 }
244 }
245
246 void PlatformShim::set_fake_path(ManifestCategory category, std::filesystem::path const& path) {
247 // use /etc as the 'redirection path' by default since its always searched
248 redirect_path(std::filesystem::path(SYSCONFDIR) / "vulkan" / category_path_name(category), path);
249 }
250
251 void PlatformShim::redirect_dlopen_name(std::filesystem::path const& filename, std::filesystem::path const& actual_path) {
252 dlopen_redirection_map[filename] = actual_path;
253 }
254
255 bool PlatformShim::is_dlopen_redirect_name(std::filesystem::path const& filename) {
256 return dlopen_redirection_map.count(filename) == 1;
257 }
258
259 std::filesystem::path PlatformShim::query_default_redirect_path(ManifestCategory category) {
260 return std::filesystem::path(SYSCONFDIR) / "vulkan" / category_path_name(category);
261 }
262 #endif
263