• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
redirect_all_paths(fs::path const & path)32 void 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 
parse_env_var_list(std::string const & var)38 std::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 defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
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 
63 std::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 
74 D3DKMT_Adapter& D3DKMT_Adapter::add_driver_manifest_path(fs::path const& src) { return add_path(src, driver_paths); }
75 D3DKMT_Adapter& D3DKMT_Adapter::add_implicit_layer_manifest_path(fs::path const& src) {
76     return add_path(src, implicit_layer_paths);
77 }
78 D3DKMT_Adapter& D3DKMT_Adapter::add_explicit_layer_manifest_path(fs::path const& src) {
79     return add_path(src, explicit_layer_paths);
80 }
81 
82 D3DKMT_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 
90 std::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 
98 void 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 }
105 
106 void PlatformShim::set_path(ManifestCategory category, fs::path const& path) {}
107 
108 void PlatformShim::add_manifest(ManifestCategory category, fs::path const& path) {
109     if (category == ManifestCategory::implicit_layer) hkey_local_machine_implicit_layers.emplace_back(path.str());
110     if (category == ManifestCategory::explicit_layer)
111         hkey_local_machine_explicit_layers.emplace_back(path.str());
112     else
113         hkey_local_machine_drivers.emplace_back(path.str());
114 }
115 void PlatformShim::add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 desc1) {
116     dxgi_adapters.push_back(DXGIAdapter(gpu_preference, desc1, next_adapter_handle++));
117 }
118 
119 void PlatformShim::add_d3dkmt_adapter(D3DKMT_Adapter const& adapter) { d3dkmt_adapters.push_back(adapter); }
120 
121 void PlatformShim::set_app_package_path(fs::path const& path) {
122     app_package_path.resize(path.size());
123     MultiByteToWideChar(CP_UTF8, 0, path.c_str(), -1, &app_package_path[0], static_cast<int>(app_package_path.size()));
124 }
125 
126 // TODO:
127 void PlatformShim::add_CM_Device_ID(std::wstring const& id, fs::path const& icd_path, fs::path const& layer_path) {
128     //     // append a null byte as separator if there is already id's in the list
129     //     if (CM_device_ID_list.size() != 0) {
130     //         CM_device_ID_list += L'\0';  // I'm sure this wont cause issues with std::string down the line... /s
131     //     }
132     //     CM_device_ID_list += id;
133     //     std::string id_str(id.length(), '\0');
134     //     size_t size_written{};
135     //     wcstombs_s(&size_written, &id_str[0], id_str.length(), id.c_str(), id.length());
136 
137     //     std::string device_path = std::string(pnp_registry_path) + "\\" + id_str;
138     //     CM_device_ID_registry_keys.push_back(device_path.c_str());
139     //     add_key_value_string(id_key, "VulkanDriverName", icd_path.c_str());
140     //     add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str());
141     //     // TODO: decide how to handle 32 bit
142     //     // add_key_value_string(id_key, "VulkanDriverNameWoW", icd_path.c_str());
143     //     // add_key_value_string(id_key, "VulkanLayerName", layer_path.c_str());
144 }
145 
146 void PlatformShim::redirect_category(fs::path const& new_path, ManifestCategory search_category) {}
147 
148 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
149 
150 #include <dirent.h>
151 #include <unistd.h>
152 
153 std::string category_path_name(ManifestCategory category) {
154     if (category == ManifestCategory::implicit_layer) return "implicit_layer.d";
155     if (category == ManifestCategory::explicit_layer)
156         return "explicit_layer.d";
157     else
158         return "icd.d";
159 }
160 
161 void PlatformShim::reset() { redirection_map.clear(); }
162 
163 void PlatformShim::redirect_path(fs::path const& path, fs::path const& new_path) { redirection_map[path.str()] = new_path; }
164 void PlatformShim::remove_redirect(fs::path const& path) { redirection_map.erase(path.str()); }
165 bool PlatformShim::is_fake_path(fs::path const& path) { return redirection_map.count(path.str()) > 0; }
166 fs::path const& PlatformShim::get_fake_path(fs::path const& path) { return redirection_map.at(path.str()); }
167 
168 void PlatformShim::add_manifest(ManifestCategory category, fs::path const& path) {}
169 
170 void parse_and_add_env_var_override(std::vector<std::string>& paths, std::string env_var_contents) {
171     auto parsed_paths = parse_env_var_list(env_var_contents);
172     paths.insert(paths.end(), parsed_paths.begin(), parsed_paths.end());
173 }
174 
175 void PlatformShim::redirect_category(fs::path const& new_path, ManifestCategory category) {
176     std::vector<std::string> paths;
177     auto home = fs::path(get_env_var("HOME"));
178     if (home.size() != 0) {
179         paths.push_back((home / ".config").str());
180         paths.push_back((home / ".local/share").str());
181     }
182     parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_DIRS"));
183     parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_HOME"));
184     parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_DIRS"));
185     parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_HOME"));
186     if (category == ManifestCategory::explicit_layer) {
187         parse_and_add_env_var_override(paths, get_env_var("VK_LAYER_PATH", false));  // don't report failure
188     }
189     parse_and_add_env_var_override(paths, FALLBACK_DATA_DIRS);
190     parse_and_add_env_var_override(paths, FALLBACK_CONFIG_DIRS);
191 
192     auto sys_conf_dir = std::string(SYSCONFDIR);
193     if (!sys_conf_dir.empty()) {
194         paths.push_back(sys_conf_dir);
195     }
196 #if defined(EXTRASYSCONFDIR)
197     // EXTRASYSCONFDIR default is /etc, if SYSCONFDIR wasn't defined, it will have /etc put
198     // as its default. Don't want to double add it
199     auto extra_sys_conf_dir = std::string(EXTRASYSCONFDIR);
200     if (!extra_sys_conf_dir.empty() && sys_conf_dir != extra_sys_conf_dir) {
201         paths.push_back(extra_sys_conf_dir);
202     }
203 #endif
204 
205     for (auto& path : paths) {
206         if (!path.empty()) {
207             redirect_path(fs::path(path) / "vulkan" / category_path_name(category), new_path);
208         }
209     }
210 }
211 
212 void PlatformShim::set_path(ManifestCategory category, fs::path const& path) {
213     // use /etc as the 'redirection path' by default since its always searched
214     redirect_path(fs::path(SYSCONFDIR) / "vulkan" / category_path_name(category), path);
215 }
216 
217 #endif
218