You will also need to direct your new loader to the MoltenVK ICD:
- export VK_ICD_FILENAMES=<path to MoltenVK repository>/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
+ export VK_DRIVER_FILES=<path to MoltenVK repository>/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
To run the loader test script, change to the `build/tests` directory in your
Vulkan-Loader repository, and run:
This could be for many reasons including using a beta driver, or forcing the
loader to skip a problematic driver.
In order to support this, the loader can be forced to look at specific
-drivers with the `VK_ICD_FILENAMES` environment variable.
+drivers with either the `VK_DRIVER_FILES` or the older `VK_ICD_FILENAMES`
+environment variable.
+Both these environment variables behave the same, but `VK_ICD_FILENAMES`
+should be considered deprecated.
-The `VK_ICD_FILENAMES` environment variable is a list of Driver Manifest
+The `VK_DRIVER_FILES` environment variable is a list of Driver Manifest
files, containing the full path to the driver JSON Manifest file.
This list is colon-separated on Linux and macOS, and semicolon-separated on
Windows.
-Typically, `VK_ICD_FILENAMES` will only contain a full pathname to one info
+Typically, `VK_DRIVER_FILES` will only contain a full pathname to one info
file for a single driver.
A separator (colon or semicolon) is only used if more than one driver is needed.
+### Additional Driver Discovery
+
+There may be times that a developer wishes to force the loader to use a specific
+Driver in addition to the standard drivers (without replacing the standard
+search paths.
+The `VK_ADD_DRIVER_FILES` environment variable can be used to add a list of
+Driver Manifest files, containing the full path to the driver JSON Manifest file.
+This list is colon-separated on Linux and macOS, and semicolon-separated on
+Windows.
+It will be added prior to the standard driver search files.
+
#### Exception for Elevated Privileges
-For security reasons, `VK_ICD_FILENAMES` is ignored if running the Vulkan
-application with elevated privileges.
-Because of this, `VK_ICD_FILENAMES` can only be used for applications that do not
-use elevated privileges.
+For security reasons, `VK_ICD_FILENAMES`, `VK_DRIVER_FILES` and
+`VK_ADD_DRIVER_FILES` are all ignored if running the Vulkan application with
+elevated privileges.
+Because of this, these environment variables can only be used for applications
+that do not use elevated privileges.
For more information see
[Elevated Privilege Caveats](LoaderInterfaceArchitecture.md#elevated-privilege-caveats)
##### On Windows
```
-set VK_ICD_FILENAMES=\windows\system32\nv-vk64.json
+set VK_DRIVER_FILES=\windows\system32\nv-vk64.json
```
-This is an example which is using the `VK_ICD_FILENAMES` override on Windows to
+This is an example which is using the `VK_DRIVER_FILES` override on Windows to
point to the Nvidia Vulkan Driver's Manifest file.
+```
+set VK_ADD_DRIVER_FILES=\windows\system32\nv-vk64.json
+```
+
+This is an example which is using the `VK_ADD_DRIVER_FILES` on Windows to
+point to the Nvidia Vulkan Driver's Manifest file which will be loaded first
+before all other drivers.
+
##### On Linux
```
-export VK_ICD_FILENAMES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64.json
+export VK_DRIVER_FILES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64.json
```
-This is an example which is using the `VK_ICD_FILENAMES` override on Linux to
+This is an example which is using the `VK_DRIVER_FILES` override on Linux to
point to the Intel Mesa Driver's Manifest file.
+```
+export VK_ADD_DRIVER_FILES=/home/user/dev/mesa/share/vulkan/icd.d/intel_icd.x86_64.json
+```
+
+This is an example which is using the `VK_ADD_DRIVER_FILES` on Linux to
+point to the Intel Mesa Driver's Manifest file which will be loaded first
+before all other drivers.
+
##### On macOS
```
-export VK_ICD_FILENAMES=/home/user/MoltenVK/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
+export VK_DRIVER_FILES=/home/user/MoltenVK/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json
```
-This is an example which is using the `VK_ICD_FILENAMES` override on macOS to
+This is an example which is using the `VK_DRIVER_FILES` override on macOS to
point to an installation and build of the MoltenVK GitHub repository that
contains the MoltenVK driver.
[Driver Manifest File Format](#driver-manifest-file-format)
section for more details.
-It is also important to note that while `VK_LAYER_PATH` will point the loader
+It is also important to note that while `VK_DRIVER_FILES` will point the loader
to finding the manifest files, it does not guarantee the library files mentioned
by the manifest will immediately be found.
Often, the Driver Manifest file will point to the library file using a
In this case, there should be a way to allow developers to point to such an
ICD without modifying the system-installed ICD(s) on their system.
-This need is met with the use of the `VK_ICD_FILENAMES` environment variable,
+This need is met with the use of the `VK_DRIVER_FILES` environment variable,
which will override the mechanism used for finding system-installed
drivers.
-In other words, only the drivers listed in `VK_ICD_FILENAMES` will be
+In other words, only the drivers listed in `VK_DRIVER_FILES` will be
used.
See
<tr>
<td><small><b>LDP_LOADER_13</b></small></td>
<td>A loader <b>must</b> not load from user-defined paths (including the
- use of the <i>VK_ICD_FILENAMES</i> environment variable) when running
- elevated (Administrator/Super-user) applications.<br/>
+ use of any of <i>VK_ICD_FILENAMES</i>, <i>VK_DRIVER_FILES</i>, or
+ <i>VK_ADD_DRIVER_FILES</i> environment variables) when running elevated
+ (Administrator/Super-user) applications.<br/>
<b>This is for security reasons.</b>
</td>
<td>The behavior is undefined and may result in computer security lapses,
These behaviors also result in ignoring certain environment variables, such as:
- * `VK_ICD_FILENAMES`
+ * `VK_DRIVER_FILES` / `VK_ICD_FILENAMES`
+ * `VK_ADD_DRIVER_FILES`
* `VK_LAYER_PATH`
+ * `VK_ADD_LAYER_PATH`
* `XDG_CONFIG_HOME` (Linux/Mac-specific)
* `XDG_DATA_HOME` (Linux/Mac-specific)
<th>Example Format</th>
</tr>
<tr>
- <td><small><i>VK_ICD_FILENAMES</i></small></td>
- <td>Force the loader to use the specific ICD JSON files.
+ <td><small><i>VK_ADD_DRIVER_FILES</i></small></td>
+ <td>Provide a list of additional driver JSON files that the loader will use
+ in addition to the drivers that the loader would find normally.
+ The list of drivers will be added first, prior to the list of drivers
+ that would be found normally.
The value contains a list of delimited full path listings to
driver JSON Manifest files.<br/>
<b>NOTE:</b> If a global path to the JSON file is not used, issues
for more information.
</td>
<td><small>export<br/>
- VK_ICD_FILENAMES=<br/>
+ VK_ADD_DRIVER_FILES=<br/>
<folder_a>/intel.json:<folder_b>/amd.json
<br/> <br/>
set<br/>
- VK_ICD_FILENAMES=<br/>
+ VK_ADD_DRIVER_FILES=<br/>
+ <folder_a>\nvidia.json;<folder_b>\mesa.json
+ </small>
+ </td>
+ </tr>
+ <tr>
+ <td><small><i>VK_ADD_LAYER_PATH</i></small></td>
+ <td>Provide a list of additional paths that the loader will use to search
+ for layers in addition to the loader's standard Layer library search
+ folder when looking for explicit layer manifest files.
+ The paths will be added first, prior to the list of folders that would
+ be searched normally.
+ <br/>
+ <b>Ignored when running Vulkan application in executing with
+ elevated privileges.</b>
+ See <a href="#elevated-privilege-caveats">Elevated Privilege Caveats</a>
+ for more information.
+ </td>
+ <td><small>export<br/>
+ VK_ADD_LAYER_PATH=<br/>
+ <path_a>;<path_b><br/><br/>
+ set<br/>
+ VK_ADD_LAYER_PATH=<br/>
+ <path_a>;<path_b></small>
+ </td>
+ </tr>
+ <tr>
+ <td><small><i>VK_DRIVER_FILES</i></small></td>
+ <td>Force the loader to use the specific driver JSON files.
+ The value contains a list of delimited full path listings to
+ driver JSON Manifest files.<br/>
+ This has replaced the older deprecated environment variable
+ <i>VK_ICD_FILENAMES</i>, however the older environment variable will
+ continue to work for some time.
+ <b>NOTE:</b> If a global path to the JSON file is not used, issues
+ may be encountered.<br/>
+ <b>Ignored when running Vulkan application in executing with
+ elevated privileges.</b>
+ See <a href="#elevated-privilege-caveats">Elevated Privilege Caveats</a>
+ for more information.
+ </td>
+ <td><small>export<br/>
+ VK_DRIVER_FILES=<br/>
+ <folder_a>/intel.json:<folder_b>/amd.json
+ <br/> <br/>
+ set<br/>
+ VK_DRIVER_FILES=<br/>
<folder_a>\nvidia.json;<folder_b>\mesa.json
</small>
</td>
loader before returning the set of physical devices to layers.<br/>
</td>
<td><small>set VK_LOADER_DISABLE_SELECT=1</small>
- </td>
</tr>
<tr>
<td><small><i>VK_LOADER_DISABLE_INST_EXT_FILTER</i></small></td>
that variable for explicit layer manifest files instead of using the information
provided by the explicit layer registry keys.
-For security reasons, `VK_LAYER_PATH` is ignored if running with elevated
-privileges.
+If `VK_ADD_LAYER_PATH` is defined, then the loader will look at the provided
+paths for explicit layer manifest files in addition to using the information
+provided by the explicit layer registry keys.
+The paths provided by `VK_ADD_LAYER_PATH` are added before the standard list
+of search folders and will therefore be searched first.
+
+For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
+if running with elevated privileges.
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
for more info.
If `VK_LAYER_PATH` is defined, then the loader will look at the paths defined by
that variable for explicit layer manifest files instead of using the information
-provided by the explicit layer paths.
+provided by the standard explicit layer paths mentioned above.
+
+If `VK_ADD_LAYER_PATH` is defined, then the loader will look at the provided
+paths for explicit layer manifest files in addition to using the information
+provided by the standard explicit layer paths mentioned above.
+The paths provided by `VK_ADD_LAYER_PATH` are added before the standard list
+of search folders and will therefore be searched first.
-For security reasons, `VK_LAYER_PATH` is ignored if running with elevated
-privileges.
+For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
+if running with elevated privileges.
See [Exception for Elevated Privileges](#exception-for-elevated-privileges)
for more info.
in the [LoaderApplicationInterface.md document](LoaderApplicationInterface.md)
for more information on this.
-It is also important to note that while `VK_LAYER_PATH` will point the loader
-to finding the manifest files, it does not guarantee the library files mentioned
-by the manifest will immediately be found.
+It is also important to note that while both `VK_LAYER_PATH` and
+`VK_ADD_LAYER_PATH` will point the loader paths to search for finding the
+manifest files, it does not guarantee the library files mentioned by the
+manifest will immediately be found.
Often, the layer manifest file will point to the library file using a relative
or absolute path.
When a relative or absolute path is used, the loader can typically find the
### Exception for Elevated Privileges
-There is an exception to when `VK_LAYER_PATH` is available for use.
-For security reasons, `VK_LAYER_PATH` is ignored if running the Vulkan
-application with elevated privileges.
-Because of this, `VK_LAYER_PATH` can only be used for applications that do not
-use elevated privileges.
+There is an exception to when either `VK_LAYER_PATH` or `VK_ADD_LAYER_PATH` are
+available for use.
+For security reasons, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` are ignored
+if running the Vulkan application with elevated privileges.
+Because of this, both `VK_LAYER_PATH` and `VK_ADD_LAYER_PATH` can only be used
+for applications that do not use elevated privileges.
For more information see
[Elevated Privilege Caveats](LoaderInterfaceArchitecture.md#elevated-privilege-caveats)
<tr>
<td><small><b>LLP_LOADER_13</b></small></td>
<td>A loader <b>must</b> not load from user-defined paths (including the
- use of the <i>VK_LAYER_PATH</i> environment variable) when running
- elevated (Administrator/Super-user) applications.<br/>
+ use of either <i>VK_LAYER_PATH</i> or <i>VK_ADD_LAYER_PATH</i>
+ environment variables) when running elevated (Administrator/Super-user)
+ applications.<br/>
<b>This is for security reasons.</b>
</td>
<td>The behavior is undefined and may result in computer security lapses,
#endif // _WIN32
}
+static bool is_json(const char *path, size_t len) {
+ if (len < 5) {
+ return false;
+ }
+ return !strncmp(path, ".json", 5);
+}
+
// Handle error from to library loading
void loader_handle_load_library_error(const struct loader_instance *inst, const char *filename,
enum loader_layer_library_status *lib_status) {
return path_size;
}
-static inline void copy_data_file_path(const char *cur_path, const char *relative_path, size_t relative_path_size,
+static inline void copy_data_file_info(const char *cur_path, const char *relative_path, size_t relative_path_size,
char **output_path) {
if (NULL != cur_path) {
uint32_t start = 0;
memcpy(cur_write, &cur_path[start], s);
cur_write += s;
- // If last symbol written was not a directory symbol, add it.
- if (*(cur_write - 1) != DIRECTORY_SYMBOL) {
- *cur_write++ = DIRECTORY_SYMBOL;
+ // If this is a specific JSON file, just add it and don't add any
+ // relative path or directory symbol to it.
+ if (!is_json(cur_write - 5, s)) {
+ // Add the relative directory if present.
+ if (relative_path_size > 0) {
+ // If last symbol written was not a directory symbol, add it.
+ if (*(cur_write - 1) != DIRECTORY_SYMBOL) {
+ *cur_write++ = DIRECTORY_SYMBOL;
+ }
+ memcpy(cur_write, relative_path, relative_path_size);
+ cur_write += relative_path_size;
+ }
}
- if (relative_path_size > 0) {
- memcpy(cur_write, relative_path, relative_path_size);
- cur_write += relative_path_size;
- }
*cur_write++ = PATH_SEPARATOR;
start = stop;
}
// Look for files ending with ".json" suffix
size_t name_len = strlen(file_name);
const char *name_suffix = file_name + name_len - 5;
- if ((name_len < 5) || 0 != strncmp(name_suffix, ".json", 5)) {
+ if (!is_json(name_suffix, name_len)) {
// Use incomplete to indicate invalid name, but to keep going.
vk_result = VK_INCOMPLETE;
goto out;
return vk_result;
}
-VkResult add_data_files_in_path(const struct loader_instance *inst, char *search_path, bool is_directory_list,
- struct loader_data_files *out_files, bool use_first_found_manifest) {
+// Add any files found in the search_path. If any path in the search path points to a specific JSON, attempt to
+// only open that one JSON. Otherwise, if the path is a folder, search the folder for JSON files.
+VkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_data_files *out_files,
+ bool use_first_found_manifest) {
VkResult vk_result = VK_SUCCESS;
DIR *dir_stream = NULL;
struct dirent *dir_entry;
cur_file = next_file;
next_file = loader_get_next_path(cur_file);
- // Get the next name in the list and verify it's valid
- if (is_directory_list) {
- dir_stream = loader_opendir(inst, cur_file);
- if (NULL == dir_stream) {
- continue;
- }
- while (1) {
- dir_entry = readdir(dir_stream);
- if (NULL == dir_entry) {
- break;
- }
-
- name = &(dir_entry->d_name[0]);
- loader_get_fullpath(name, cur_file, sizeof(full_path), full_path);
- name = full_path;
-
- VkResult local_res;
- local_res = add_if_manifest_file(inst, name, out_files);
-
- // Incomplete means this was not a valid data file.
- if (local_res == VK_INCOMPLETE) {
- continue;
- } else if (local_res != VK_SUCCESS) {
- vk_result = local_res;
- break;
- }
- }
- loader_closedir(inst, dir_stream);
- if (vk_result != VK_SUCCESS) {
- goto out;
- }
- } else {
+ // Is this a JSON file, then try to open it.
+ size_t len = strlen(cur_file);
+ if (is_json(cur_file + len - 5, len)) {
#ifdef _WIN32
name = cur_file;
#else
str_len = strlen(cur_file) + 1;
}
if (str_len > sizeof(temp_path)) {
- loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "add_data_files_in_path: Path to %s too long\n", cur_file);
+ loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0, "add_data_files: Path to %s too long\n", cur_file);
continue;
}
strcpy(temp_path, cur_file);
vk_result = local_res;
break;
}
+ } else { // Otherwise, treat it as a directory
+ dir_stream = loader_opendir(inst, cur_file);
+ if (NULL == dir_stream) {
+ continue;
+ }
+ while (1) {
+ dir_entry = readdir(dir_stream);
+ if (NULL == dir_entry) {
+ break;
+ }
+
+ name = &(dir_entry->d_name[0]);
+ loader_get_fullpath(name, cur_file, sizeof(full_path), full_path);
+ name = full_path;
+
+ VkResult local_res;
+ local_res = add_if_manifest_file(inst, name, out_files);
+
+ // Incomplete means this was not a valid data file.
+ if (local_res == VK_INCOMPLETE) {
+ continue;
+ } else if (local_res != VK_SUCCESS) {
+ vk_result = local_res;
+ break;
+ }
+ }
+ loader_closedir(inst, dir_stream);
+ if (vk_result != VK_SUCCESS) {
+ goto out;
+ }
}
if (use_first_found_manifest && out_files->count > 0) {
break;
// Look for data files in the provided paths, but first check the environment override to determine if we should use that
// instead.
-static VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enum loader_data_files_type data_file_type,
- const char *env_override, const char *path_override, const char *relative_location,
- bool *override_active, struct loader_data_files *out_files) {
+static VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enum loader_json_type json_type,
+ const char *path_override, bool *override_active,
+ struct loader_data_files *out_files) {
VkResult vk_result = VK_SUCCESS;
- bool is_directory_list = true;
- bool is_icd = (data_file_type == LOADER_DATA_FILE_MANIFEST_ICD);
+ bool is_icd = false;
char *override_env = NULL;
const char *override_path = NULL;
+ char *relative_location = NULL;
+ char *additional_env = NULL;
size_t search_path_size = 0;
char *search_path = NULL;
char *cur_path_ptr = NULL;
char *home = NULL;
char *default_data_home = NULL;
char *default_config_home = NULL;
+ char *home_data_dir = NULL;
+ char *home_config_dir = NULL;
// Only use HOME if XDG_DATA_HOME is not present on the system
home = loader_secure_getenv("HOME", inst);
strcat(default_data_home, data_suffix);
}
}
+
+ if (NULL != default_config_home) {
+ home_config_dir = default_config_home;
+ } else {
+ home_config_dir = xdg_config_home;
+ }
+ if (NULL != default_data_home) {
+ home_data_dir = default_data_home;
+ } else {
+ home_data_dir = xdg_data_home;
+ }
#endif // !_WIN32
+ switch (json_type) {
+ case VULKAN_LOADER_JSON_DRIVER:
+ is_icd = true;
+ override_env = loader_secure_getenv(VK_DRIVER_FILES_ENV_VAR, inst);
+ if (NULL == override_env) {
+ // Not there, so fall back to the old name
+ override_env = loader_secure_getenv(VK_ICD_FILENAMES_ENV_VAR, inst);
+ }
+ additional_env = loader_secure_getenv(VK_ADDITIONAL_DRIVER_FILES_ENV_VAR, inst);
+ relative_location = VK_DRIVERS_INFO_RELATIVE_DIR;
+ break;
+ case VULKAN_LOADER_JSON_IMPLICIT_LAYER:
+ relative_location = VK_ILAYERS_INFO_RELATIVE_DIR;
+ break;
+ case VULKAN_LOADER_JSON_EXPLICIT_LAYER:
+ override_env = loader_secure_getenv(VK_LAYER_PATH_ENV_VAR, inst);
+ additional_env = loader_secure_getenv(VK_ADDITIONAL_LAYER_PATH_ENV_VAR, inst);
+ relative_location = VK_ELAYERS_INFO_RELATIVE_DIR;
+ break;
+ }
+
if (path_override != NULL) {
override_path = path_override;
- } else if (env_override != NULL) {
- override_env = loader_secure_getenv(env_override, inst);
-
- // The ICD override is actually a specific list of filenames, not directories
- if (is_icd && NULL != override_env) {
- is_directory_list = false;
- }
+ } else if (override_env != NULL) {
override_path = override_env;
}
// If there's an override, use that (and the local folder if required) and nothing else
if (NULL != override_path) {
// Local folder and null terminator
- search_path_size += strlen(override_path) + 1;
+ search_path_size += strlen(override_path) + 2;
+
+ // Add the size of any additional search paths defined in the additive environment variable
+ if (NULL != additional_env) {
+ search_path_size += determine_data_file_path_size(additional_env, 0) + 2;
+ }
} else if (NULL == relative_location) {
// If there's no override, and no relative location, bail out. This is usually
// the case when we're on Windows and the default path is to use the registry.
goto out;
} else {
+ // Add the size of any additional search paths defined in the additive environment variable
+ if (NULL != additional_env) {
+ search_path_size += determine_data_file_path_size(additional_env, 0) + 2;
+#ifdef _WIN32
+ } else {
+ goto out;
+ }
+#else // !_WIN32
+ }
+
// Add the general search folders (with the appropriate relative folder added)
rel_size = strlen(relative_location);
- if (rel_size == 0) {
- goto out;
- } else {
+ if (rel_size > 0) {
#if defined(__APPLE__)
search_path_size += MAXPATHLEN;
#endif
-#ifndef _WIN32
- // Only add the home folders if not ICD filenames or superuser
- if (is_directory_list && !is_high_integrity()) {
- if (NULL != default_config_home) {
- search_path_size += determine_data_file_path_size(default_config_home, rel_size);
- } else {
- search_path_size += determine_data_file_path_size(xdg_config_home, rel_size);
- }
+ // Only add the home folders if defined
+ if (NULL != home_config_dir) {
+ search_path_size += determine_data_file_path_size(home_config_dir, rel_size);
}
search_path_size += determine_data_file_path_size(xdg_config_dirs, rel_size);
search_path_size += determine_data_file_path_size(SYSCONFDIR, rel_size);
#if defined(EXTRASYSCONFDIR)
search_path_size += determine_data_file_path_size(EXTRASYSCONFDIR, rel_size);
#endif
- // Only add the home folders if not ICD filenames or superuser
- if (is_directory_list && !is_high_integrity()) {
- if (NULL != default_data_home) {
- search_path_size += determine_data_file_path_size(default_data_home, rel_size);
- } else {
- search_path_size += determine_data_file_path_size(xdg_data_home, rel_size);
- }
+ // Only add the home folders if defined
+ if (NULL != home_data_dir) {
+ search_path_size += determine_data_file_path_size(home_data_dir, rel_size);
}
search_path_size += determine_data_file_path_size(xdg_data_dirs, rel_size);
-#endif // !_WIN32
}
+#endif // !_WIN32
}
// Allocate the required space
// Add the remaining paths to the list
if (NULL != override_path) {
strcpy(cur_path_ptr, override_path);
+ cur_path_ptr += strlen(override_path);
+ if (NULL != additional_env) {
+ *cur_path_ptr++ = PATH_SEPARATOR;
+
+ copy_data_file_info(additional_env, NULL, 0, &cur_path_ptr);
+
+ // Remove the last path separator
+ --cur_path_ptr;
+ *cur_path_ptr = '\0';
+ }
} else {
+ // Add any additional search paths defined in the additive environment variable
+ if (NULL != additional_env) {
+ copy_data_file_info(additional_env, NULL, 0, &cur_path_ptr);
+ }
+
#ifndef _WIN32
if (rel_size > 0) {
#if defined(__APPLE__)
cur_path_ptr += rel_size;
*cur_path_ptr++ = PATH_SEPARATOR;
// only for ICD manifests
- if (env_override != NULL && strcmp(VK_ICD_FILENAMES_ENV_VAR, env_override) == 0) {
+ if (override_env != NULL && is_icd) {
use_first_found_manifest = true;
}
}
}
}
#endif // __APPLE__
- // Only add the home folders if not ICD filenames or superuser
- if (is_directory_list && !is_high_integrity()) {
- if (NULL != default_config_home) {
- copy_data_file_path(default_config_home, relative_location, rel_size, &cur_path_ptr);
- } else {
- copy_data_file_path(xdg_config_home, relative_location, rel_size, &cur_path_ptr);
- }
+
+ // Only add the home folders if not NULL
+ if (NULL != home_config_dir) {
+ copy_data_file_info(home_config_dir, relative_location, rel_size, &cur_path_ptr);
}
- copy_data_file_path(xdg_config_dirs, relative_location, rel_size, &cur_path_ptr);
- copy_data_file_path(SYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
+ copy_data_file_info(xdg_config_dirs, relative_location, rel_size, &cur_path_ptr);
+ copy_data_file_info(SYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
#if defined(EXTRASYSCONFDIR)
- copy_data_file_path(EXTRASYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
+ copy_data_file_info(EXTRASYSCONFDIR, relative_location, rel_size, &cur_path_ptr);
#endif
- // Only add the home folders if not ICD filenames or superuser
- if (is_directory_list && !is_high_integrity()) {
- if (NULL != default_data_home) {
- copy_data_file_path(default_data_home, relative_location, rel_size, &cur_path_ptr);
- } else {
- copy_data_file_path(xdg_data_home, relative_location, rel_size, &cur_path_ptr);
- }
+ // Only add the home folders if not NULL
+ if (NULL != home_data_dir) {
+ copy_data_file_info(home_data_dir, relative_location, rel_size, &cur_path_ptr);
}
- copy_data_file_path(xdg_data_dirs, relative_location, rel_size, &cur_path_ptr);
+ copy_data_file_info(xdg_data_dirs, relative_location, rel_size, &cur_path_ptr);
}
// Remove the last path separator
if (NULL != tmp_search_path) {
strncpy(tmp_search_path, search_path, search_path_size);
tmp_search_path[search_path_size] = '\0';
- if (data_file_type == LOADER_DATA_FILE_MANIFEST_ICD) {
+ if (is_icd) {
log_flags = VULKAN_LOADER_DRIVER_BIT;
loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Searching for driver manifest files");
} else {
}
// Now, parse the paths and add any manifest files found in them.
- vk_result = add_data_files_in_path(inst, search_path, is_directory_list, out_files, use_first_found_manifest);
+ vk_result = add_data_files(inst, search_path, out_files, use_first_found_manifest);
if (log_flags != 0 && out_files->count > 0) {
loader_log(inst, log_flags, 0, " Found the following files:");
out:
+ if (NULL != additional_env) {
+ loader_free_getenv(additional_env, inst);
+ }
if (NULL != override_env) {
loader_free_getenv(override_env, inst);
}
// Find the Vulkan library manifest files.
//
-// This function scans the "location" or "env_override" directories/files
-// for a list of JSON manifest files. If env_override is non-NULL
-// and has a valid value. Then the location is ignored. Otherwise
-// location is used to look for manifest files. The location
-// is interpreted as Registry path on Windows and a directory path(s)
-// on Linux. "home_location" is an additional directory in the users home
-// directory to look at. It is expanded into the dir path
-// $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
-// on environment variables. This "home_location" is only used on Linux.
+// This function scans the appropriate locations for a list of JSON manifest files based on the
+// "json_type". The location is interpreted as Registry path on Windows and a directory path(s)
+// on Linux.
+// "home_location" is an additional directory in the users home directory to look at. It is
+// expanded into the dir path $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location
+// depending on environment variables. This "home_location" is only used on Linux.
//
// \returns
// VKResult
// Win Layer | files | dirs
// Linux ICD | dirs | files
// Linux Layer| dirs | dirs
-VkResult loader_get_data_files(const struct loader_instance *inst, enum loader_data_files_type data_file_type,
- bool warn_if_not_present, const char *env_override, const char *path_override,
- char *registry_location, const char *relative_location, struct loader_data_files *out_files) {
+
+VkResult loader_get_data_files(const struct loader_instance *inst, enum loader_json_type json_type, const char *path_override,
+ struct loader_data_files *out_files) {
VkResult res = VK_SUCCESS;
bool override_active = false;
out_files->alloc_count = 0;
out_files->filename_list = NULL;
- res = read_data_files_in_search_paths(inst, data_file_type, env_override, path_override, relative_location, &override_active,
- out_files);
+ res = read_data_files_in_search_paths(inst, json_type, path_override, &override_active, out_files);
if (VK_SUCCESS != res) {
goto out;
}
#ifdef _WIN32
// Read the registry if the override wasn't active.
if (!override_active) {
- res = windows_read_data_files_in_registry(inst, data_file_type, warn_if_not_present, registry_location, out_files);
- if (VK_SUCCESS != res) {
+ bool warn_if_not_present = false;
+ char *registry_location = NULL;
+ enum loader_data_files_type manifest_type = LOADER_DATA_FILE_MANIFEST_DRIVER;
+
+ switch (json_type) {
+ default:
+ goto out;
+ case VULKAN_LOADER_JSON_DRIVER:
+ warn_if_not_present = true;
+ registry_location = VK_DRIVERS_INFO_REGISTRY_LOC;
+ break;
+ case VULKAN_LOADER_JSON_IMPLICIT_LAYER:
+ manifest_type = LOADER_DATA_FILE_MANIFEST_LAYER;
+ registry_location = VK_ILAYERS_INFO_REGISTRY_LOC;
+ break;
+ case VULKAN_LOADER_JSON_EXPLICIT_LAYER:
+ warn_if_not_present = true;
+ manifest_type = LOADER_DATA_FILE_MANIFEST_LAYER;
+ registry_location = VK_ELAYERS_INFO_REGISTRY_LOC;
+ break;
+ }
+ VkResult tmp_res =
+ windows_read_data_files_in_registry(inst, manifest_type, warn_if_not_present, registry_location, out_files);
+ // Only return an error if there was an error this time, and no manifest files from before.
+ if (VK_SUCCESS != tmp_res && out_files->count == 0) {
+ res = tmp_res;
goto out;
}
}
// Try to find the Vulkan ICD driver(s).
//
-// This function scans the default system loader path(s) or path
-// specified by the \c VK_ICD_FILENAMES environment variable in
-// order to find loadable VK ICDs manifest files. From these
-// manifest files it finds the ICD libraries.
+// This function scans the default system loader path(s) or path specified by either the
+// VK_DRIVER_FILES or VK_ICD_FILENAMES environment variable in order to find loadable
+// VK ICDs manifest files.
+// From these manifest files it finds the ICD libraries.
//
// \returns
// Vulkan result
goto out;
}
// Get a list of manifest files for ICDs
- res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_ICD, true, VK_ICD_FILENAMES_ENV_VAR, NULL,
- VK_DRIVERS_INFO_REGISTRY_LOC, VK_DRIVERS_INFO_RELATIVE_DIR, &manifest_files);
+ res = loader_get_data_files(inst, VULKAN_LOADER_JSON_DRIVER, NULL, &manifest_files);
if (VK_SUCCESS != res || manifest_files.count == 0) {
goto out;
}
loader_platform_thread_lock_mutex(&loader_json_lock);
// Get a list of manifest files for any implicit layers
- // Pass NULL for environment variable override - implicit layers are not overridden by LAYERS_PATH_ENV
- if (VK_SUCCESS != loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_LAYER, false, NULL, NULL, VK_ILAYERS_INFO_REGISTRY_LOC,
- VK_ILAYERS_INFO_RELATIVE_DIR, &manifest_files)) {
+ if (VK_SUCCESS != loader_get_data_files(inst, VULKAN_LOADER_JSON_IMPLICIT_LAYER, NULL, &manifest_files)) {
goto out;
}
}
cur_write_ptr = &override_paths[0];
for (uint32_t j = 0; j < prop->num_override_paths; j++) {
- copy_data_file_path(prop->override_paths[j], NULL, 0, &cur_write_ptr);
+ copy_data_file_info(prop->override_paths[j], NULL, 0, &cur_write_ptr);
}
// Remove the last path separator
--cur_write_ptr;
}
// Get a list of manifest files for explicit layers
- if (VK_SUCCESS != loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, VK_LAYER_PATH_ENV_VAR, override_paths,
- VK_ELAYERS_INFO_REGISTRY_LOC, VK_ELAYERS_INFO_RELATIVE_DIR, &manifest_files)) {
+ if (VK_SUCCESS != loader_get_data_files(inst, VULKAN_LOADER_JSON_EXPLICIT_LAYER, override_paths, &manifest_files)) {
goto out;
}
// a failure occurs before allocating the manifest filename_list.
memset(&manifest_files, 0, sizeof(struct loader_data_files));
- // Pass NULL for environment variable override - implicit layers are not overridden by LAYERS_PATH_ENV
- VkResult res = loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_LAYER, false, NULL, NULL, VK_ILAYERS_INFO_REGISTRY_LOC,
- VK_ILAYERS_INFO_RELATIVE_DIR, &manifest_files);
+ VkResult res = loader_get_data_files(inst, VULKAN_LOADER_JSON_IMPLICIT_LAYER, NULL, &manifest_files);
if (VK_SUCCESS != res || manifest_files.count == 0) {
goto out;
}
}
cur_write_ptr = &override_paths[0];
for (uint32_t j = 0; j < prop->num_override_paths; j++) {
- copy_data_file_path(prop->override_paths[j], NULL, 0, &cur_write_ptr);
+ copy_data_file_info(prop->override_paths[j], NULL, 0, &cur_write_ptr);
}
// Remove the last path separator
--cur_write_ptr;
// explicit layer info as well. Not to worry, though, all explicit layers not included
// in the override layer will be removed below in loader_remove_layers_in_blacklist().
if (override_layer_valid || implicit_metalayer_present) {
- if (VK_SUCCESS != loader_get_data_files(inst, LOADER_DATA_FILE_MANIFEST_LAYER, true, VK_LAYER_PATH_ENV_VAR, override_paths,
- VK_ELAYERS_INFO_REGISTRY_LOC, VK_ELAYERS_INFO_RELATIVE_DIR, &manifest_files)) {
+ if (VK_SUCCESS != loader_get_data_files(inst, VULKAN_LOADER_JSON_EXPLICIT_LAYER, override_paths, &manifest_files)) {
goto out;
}
// If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
// find a suitable ICD.
if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
+ loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "terminator_CreateInstance: Found no drivers!");
res = VK_ERROR_INCOMPATIBLE_DRIVER;
}
VkStringErrorFlags vk_string_validate(const int max_length, const char *char_array);
char *loader_get_next_path(char *path);
-VkResult add_data_files_in_path(const struct loader_instance *inst, char *search_path, bool is_directory_list,
- struct loader_data_files *out_files, bool use_first_found_manifest);
\ No newline at end of file
+VkResult add_data_files(const struct loader_instance *inst, char *search_path, struct loader_data_files *out_files,
+ bool use_first_found_manifest);
#include "vk_loader_platform.h"
+enum loader_json_type {
+ VULKAN_LOADER_JSON_DRIVER = 0,
+ VULKAN_LOADER_JSON_IMPLICIT_LAYER,
+ VULKAN_LOADER_JSON_EXPLICIT_LAYER,
+};
+
enum layer_type_flags {
VK_LAYER_TYPE_FLAG_INSTANCE_LAYER = 0x1, // If not set, indicates Device layer
VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER = 0x2, // If not set, indicates Implicit layer
};
enum loader_data_files_type {
- LOADER_DATA_FILE_MANIFEST_ICD = 0,
+ LOADER_DATA_FILE_MANIFEST_DRIVER = 0,
LOADER_DATA_FILE_MANIFEST_LAYER,
LOADER_DATA_FILE_NUM_TYPES // Not a real field, used for possible loop terminator
};
CONFIGRET status = CM_Open_DevNode_Key(dev_id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkrKey, CM_REGISTRY_SOFTWARE);
if (status != CR_SUCCESS) {
- loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
"windows_get_device_registry_entry: Failed to open registry key for DeviceID(%d)", dev_id);
*result = VK_ERROR_INCOMPATIBLE_DRIVER;
return false;
if (ret != ERROR_SUCCESS) {
if (ret == ERROR_FILE_NOT_FOUND) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
"windows_get_device_registry_entry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name);
} else {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s size",
- dev_id, value_name);
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name);
}
goto out;
}
manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (manifest_path == NULL) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_device_registry_entry: Failed to allocate space for DriverName.");
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "windows_get_device_registry_entry: Failed to allocate space for DriverName.");
*result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto out;
}
ret = RegQueryValueEx(hkrKey, value_name, NULL, &data_type, (BYTE *)manifest_path, &requiredSize);
if (ret != ERROR_SUCCESS) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s",
- value_name);
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s", value_name);
*result = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out;
}
if (data_type != REG_SZ && data_type != REG_MULTI_SZ) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
"windows_get_device_registry_entry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name);
*result = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out;
return found;
}
-VkResult windows_get_device_registry_files(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size,
- LPCSTR value_name) {
+VkResult windows_get_device_registry_files(const struct loader_instance *inst, uint32_t log_target_flag, char **reg_data,
+ PDWORD reg_data_size, LPCSTR value_name) {
static const wchar_t *softwareComponentGUID = L"{5c4c3332-344d-483c-8739-259e934c9cc8}";
static const wchar_t *displayGUID = L"{4d36e968-e325-11ce-bfc1-08002be10318}";
#ifdef CM_GETIDLIST_FILTER_PRESENT
pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (pDeviceNames == NULL) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
"windows_get_device_registry_files: Failed to allocate space for display device names.");
result = VK_ERROR_OUT_OF_HOST_MEMORY;
return result;
for (wchar_t *deviceName = pDeviceNames; *deviceName; deviceName += wcslen(deviceName) + 1) {
CONFIGRET status = CM_Locate_DevNodeW(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
if (CR_SUCCESS != status) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_device_registry_files: failed to open DevNode %ls",
- deviceName);
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
+ "windows_get_device_registry_files: failed to open DevNode %ls", deviceName);
continue;
}
ULONG ulStatus, ulProblem;
status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
if (CR_SUCCESS != status) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_device_registry_files: failed to probe device status %ls",
- deviceName);
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
+ "windows_get_device_registry_files: failed to probe device status %ls", deviceName);
continue;
}
if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART)) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"windows_get_device_registry_files: device %ls is pending reboot, skipping ...", deviceName);
continue;
}
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "windows_get_device_registry_files: opening device %ls", deviceName);
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, "windows_get_device_registry_files: opening device %ls",
+ deviceName);
if (windows_get_device_registry_entry(inst, reg_data, reg_data_size, devID, value_name, &result)) {
found = true;
status = CM_Get_Child(&childID, devID, 0);
if (status != CR_SUCCESS) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"windows_get_device_registry_files: unable to open child-device error:%d", status);
continue;
}
wchar_t buffer[MAX_DEVICE_ID_LEN];
CM_Get_Device_IDW(childID, buffer, MAX_DEVICE_ID_LEN, 0);
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "windows_get_device_registry_files: Opening child device %d - %ls",
- childID, buffer);
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
+ "windows_get_device_registry_files: Opening child device %d - %ls", childID, buffer);
status = CM_Get_DevNode_Registry_PropertyW(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
if (status != CR_SUCCESS) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
"windows_get_device_registry_files: unable to obtain GUID for:%d error:%d", childID, status);
result = VK_ERROR_INCOMPATIBLE_DRIVER;
}
if (wcscmp(childGuid, softwareComponentGUID) != 0) {
- loader_log(inst, VULKAN_LOADER_DEBUG_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_DEBUG_BIT | log_target_flag, 0,
"windows_get_device_registry_files: GUID for %d is not SoftwareComponent skipping", childID);
continue;
}
}
if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
+ loader_log(inst, log_target_flag, 0, "windows_get_device_registry_files: found no registry files");
result = VK_ERROR_INCOMPATIBLE_DRIVER;
}
bool found = false;
IDXGIFactory1 *dxgi_factory = NULL;
bool is_driver = !strcmp(location, VK_DRIVERS_INFO_REGISTRY_LOC);
+ uint32_t log_target_flag = is_driver ? VULKAN_LOADER_DRIVER_BIT : VULKAN_LOADER_LAYER_BIT;
assert(reg_data != NULL && "windows_get_registry_files: reg_data is a NULL pointer");
if (is_driver) {
HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&dxgi_factory);
if (hres != S_OK) {
- loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0,
"windows_get_registry_files: Failed to create dxgi factory for ICD registry verification. No ICDs will be "
"added from "
"legacy registry locations");
if (NULL == *reg_data) {
*reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == *reg_data) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
"windows_get_registry_files: Failed to allocate space for registry data for key %s", name);
RegCloseKey(key);
result = VK_ERROR_OUT_OF_HOST_MEMORY;
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (NULL == new_ptr) {
loader_log(
- inst, VULKAN_LOADER_ERROR_BIT, 0,
+ inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
"windows_get_registry_files: Failed to reallocate space for registry value of size %d for key %s",
*reg_data_size * 2, name);
RegCloseKey(key);
// We've now found a json file. If this is an ICD, we still need to check if there is actually a device
// that matches this ICD
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
+ "Located json file \"%s\" from registry \"%s\\%s\"", name,
hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR,
location);
if (is_driver) {
}
}
if (i == sizeof(known_drivers) / sizeof(known_drivers[0])) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"Driver %s is not recognized as a known driver. It will be assumed to be active", name);
} else {
bool found_gpu = false;
if (hres == DXGI_ERROR_NOT_FOUND) {
break;
} else if (hres != S_OK) {
- loader_log(inst, VULKAN_LOADER_WARN_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0,
"Failed to enumerate DXGI adapters at index %d. As a result, drivers may be skipped",
j);
continue;
hres = adapter->lpVtbl->GetDesc1(adapter, &description);
if (hres != S_OK) {
loader_log(
- inst, VULKAN_LOADER_INFO_BIT, 0,
+ inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"Failed to get DXGI adapter information at index %d. As a result, drivers may be skipped",
j);
continue;
}
if (!found_gpu) {
- loader_log(inst, VULKAN_LOADER_INFO_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"Dropping driver %s as no corresponding DXGI adapter was found", name);
continue;
}
found = true;
} else {
loader_log(
- inst, VULKAN_LOADER_INFO_BIT, 0,
+ inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0,
"Skipping adding of json file \"%s\" from registry \"%s\\%s\" to the list due to duplication", name,
hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR,
location);
}
if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
+ loader_log(inst, log_target_flag, 0, "Found no registry files in %s", location);
result = VK_ERROR_INCOMPATIBLE_DRIVER;
}
struct loader_data_files *out_files) {
VkResult vk_result = VK_SUCCESS;
char *search_path = NULL;
+ uint32_t log_target_flag = 0;
- if (data_file_type == LOADER_DATA_FILE_MANIFEST_ICD) {
- loader_log(inst, VULKAN_LOADER_DRIVER_BIT, 0, "Checking for Driver Manifest files in Registry at %s", registry_location);
+ if (data_file_type == LOADER_DATA_FILE_MANIFEST_DRIVER) {
+ log_target_flag = VULKAN_LOADER_DRIVER_BIT;
+ loader_log(inst, log_target_flag, 0, "Checking for Driver Manifest files in Registry at %s", registry_location);
} else {
- loader_log(inst, VULKAN_LOADER_LAYER_BIT, 0, "Checking for Driver Manifest files in Registry at %s", registry_location);
+ log_target_flag = VULKAN_LOADER_LAYER_BIT;
+ loader_log(inst, log_target_flag, 0, "Checking for Layer Manifest files in Registry at %s", registry_location);
}
// These calls look at the PNP/Device section of the registry.
// If we're looking for drivers we need to try enumerating adapters
regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpDriverRegistryWide());
if (regHKR_result == VK_INCOMPLETE) {
- regHKR_result = windows_get_device_registry_files(inst, &search_path, ®_size, LoaderPnpDriverRegistry());
+ regHKR_result =
+ windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpDriverRegistry());
}
} else if (!strncmp(registry_location, VK_ELAYERS_INFO_REGISTRY_LOC, sizeof(VK_ELAYERS_INFO_REGISTRY_LOC))) {
regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpELayerRegistryWide());
if (regHKR_result == VK_INCOMPLETE) {
- regHKR_result = windows_get_device_registry_files(inst, &search_path, ®_size, LoaderPnpELayerRegistry());
+ regHKR_result =
+ windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpELayerRegistry());
}
} else if (!strncmp(registry_location, VK_ILAYERS_INFO_REGISTRY_LOC, sizeof(VK_ILAYERS_INFO_REGISTRY_LOC))) {
regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpILayerRegistryWide());
if (regHKR_result == VK_INCOMPLETE) {
- regHKR_result = windows_get_device_registry_files(inst, &search_path, ®_size, LoaderPnpILayerRegistry());
+ regHKR_result =
+ windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpILayerRegistry());
}
}
}
if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == search_path) {
- if (data_file_type == LOADER_DATA_FILE_MANIFEST_ICD) {
- loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ if (data_file_type == LOADER_DATA_FILE_MANIFEST_DRIVER) {
+ loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0,
"windows_read_data_files_in_registry: Registry lookup failed to get ICD manifest files. Possibly missing "
"Vulkan driver?");
vk_result = VK_ERROR_INCOMPATIBLE_DRIVER;
if (warn_if_not_present) {
if (data_file_type == LOADER_DATA_FILE_MANIFEST_LAYER) {
// This is only a warning for layers
- loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0,
"windows_read_data_files_in_registry: Registry lookup failed to get layer manifest files.");
} else {
// This is only a warning for general data files
- loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0,
+ loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0,
"windows_read_data_files_in_registry: Registry lookup failed to get data files.");
}
}
}
// Now, parse the paths and add any manifest files found in them.
- vk_result = add_data_files_in_path(inst, search_path, false, out_files, false);
+ vk_result = add_data_files(inst, search_path, out_files, false);
out:
//
// *reg_data contains a string list of filenames as pointer.
// When done using the returned string list, the caller should free the pointer.
-VkResult windows_get_device_registry_files(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size,
- LPCSTR value_name);
+VkResult windows_get_device_registry_files(const struct loader_instance *inst, uint32_t log_target_flag, char **reg_data,
+ PDWORD reg_data_size, LPCSTR value_name);
// Find the list of registry files (names within a key) in key "location".
//
res = loader_icd_scan(ptr_instance, &ptr_instance->icd_tramp_list);
if (res == VK_SUCCESS && ptr_instance->icd_tramp_list.count == 0) {
// No drivers found
+ loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "vkCreateInstance: Found no drivers!");
res = VK_ERROR_INCOMPATIBLE_DRIVER;
goto out;
}
if (res != VK_SUCCESS) {
if (res != VK_ERROR_OUT_OF_HOST_MEMORY && ptr_instance->icd_tramp_list.count == 0) {
+ loader_log(ptr_instance, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, "vkCreateInstance: Found no drivers!");
res = VK_ERROR_INCOMPATIBLE_DRIVER;
}
goto out;
/*
*
- * Copyright (c) 2015-2021 The Khronos Group Inc.
- * Copyright (c) 2015-2021 Valve Corporation
- * Copyright (c) 2015-2021 LunarG, Inc.
+ * Copyright (c) 2015-2022 The Khronos Group Inc.
+ * Copyright (c) 2015-2022 Valve Corporation
+ * Copyright (c) 2015-2022 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#endif
// Environment Variable information
-#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES"
+#define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES" // Deprecated
+#define VK_DRIVER_FILES_ENV_VAR "VK_DRIVER_FILES"
+#define VK_ADDITIONAL_DRIVER_FILES_ENV_VAR "VK_ADD_DRIVER_FILES"
#define VK_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
+#define VK_ADDITIONAL_LAYER_PATH_ENV_VAR "VK_ADD_LAYER_PATH"
// Override layer information
#define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
test_regression
loader_testing_main.cpp
loader_alloc_callback_tests.cpp
+ loader_envvar_tests.cpp
loader_get_proc_addr_tests.cpp
loader_debug_ext_tests.cpp
loader_handle_validation_tests.cpp
The `reset_test_icd()` and `reset_test_layer()` are similar to the above functions but additionally
reset the layer or driver to its initial state.
Use this if you need to reset a driver during a test.
-These functions are called on the drivers and layers when the framework is being create in each test.
\ No newline at end of file
+These functions are called on the drivers and layers when the framework is being create in each test.
strncpy_s(pProperties[ext_count].extensionName, VK_MAX_EXTENSION_NAME_SIZE, VK_KHR_MAINTENANCE1_EXTENSION_NAME,
strlen(VK_KHR_MAINTENANCE1_EXTENSION_NAME) + 1);
#else
- strcpy(pProperties[ext_count].extensionName, VK_KHR_MAINTENANCE1_EXTENSION_NAME);
+ strncpy(pProperties[ext_count].extensionName, VK_KHR_MAINTENANCE1_EXTENSION_NAME, VK_MAX_EXTENSION_NAME_SIZE);
#endif
pProperties[ext_count].specVersion = 2;
ext_count++;
VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
strlen(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME) + 1);
#else
- strcpy(pProperties[ext_count].extensionName, VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME);
+ strncpy(pProperties[ext_count].extensionName, VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
+ VK_MAX_EXTENSION_NAME_SIZE);
#endif
pProperties[ext_count].specVersion = 1;
ext_count++;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
if (!strcmp(name, "CreateAndroidSurfaceKHR")) return (PFN_vkVoidFunction)wrap_vkCreateAndroidSurfaceKHR;
-#endif // VK_USE_PLATFORM_WIN32_KHR
+#endif // VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_USE_PLATFORM_WIN32_KHR
if (!strcmp(name, "CreateWin32SurfaceKHR")) return (PFN_vkVoidFunction)wrap_vkCreateWin32SurfaceKHR;
}
fs::path TestLayerHandle::get_layer_full_path() noexcept { return layer_library.lib_path; }
-FrameworkEnvironment::FrameworkEnvironment(DebugMode debug_mode) noexcept
+FrameworkEnvironment::FrameworkEnvironment(DebugMode debug_mode, bool override_icds, bool override_layers) noexcept
: platform_shim(debug_mode),
null_folder(FRAMEWORK_BUILD_DIRECTORY, "null_dir", debug_mode),
icd_folder(FRAMEWORK_BUILD_DIRECTORY, "icd_manifests", debug_mode),
vulkan_functions() {
platform_shim->redirect_all_paths(null_folder.location());
- platform_shim->set_path(ManifestCategory::icd, icd_folder.location());
- platform_shim->set_path(ManifestCategory::explicit_layer, explicit_layer_folder.location());
+ if (override_icds) {
+ platform_shim->set_path(ManifestCategory::icd, null_folder.location());
+ } else {
+ platform_shim->set_path(ManifestCategory::icd, icd_folder.location());
+ }
+ if (override_layers) {
+ platform_shim->set_path(ManifestCategory::explicit_layer, null_folder.location());
+ } else {
+ platform_shim->set_path(ManifestCategory::explicit_layer, explicit_layer_folder.location());
+ }
platform_shim->set_path(ManifestCategory::implicit_layer, implicit_layer_folder.location());
}
env_var_vk_icd_filenames += OS_ENV_VAR_LIST_SEPARATOR;
}
env_var_vk_icd_filenames += (icd_folder.location() / full_json_name).str();
- set_env_var("VK_ICD_FILENAMES", env_var_vk_icd_filenames);
+ set_env_var("VK_DRIVER_FILES", env_var_vk_icd_filenames);
+ } else if (icd_details.use_add_env_var_icd_filenames) {
+ if (!add_env_var_vk_icd_filenames.empty()) {
+ add_env_var_vk_icd_filenames += OS_ENV_VAR_LIST_SEPARATOR;
+ }
+ add_env_var_vk_icd_filenames += (icd_folder.location() / full_json_name).str();
+ set_env_var("VK_ADD_DRIVER_FILES", add_env_var_vk_icd_filenames);
} else {
platform_shim->add_manifest(ManifestCategory::icd, driver_loc);
}
BUILDER_VALUE(TestICDDetails, uint32_t, api_version, VK_API_VERSION_1_0);
BUILDER_VALUE(TestICDDetails, std::string, json_name, "test_icd");
BUILDER_VALUE(TestICDDetails, bool, use_env_var_icd_filenames, false);
+ BUILDER_VALUE(TestICDDetails, bool, use_add_env_var_icd_filenames, false);
BUILDER_VALUE(TestICDDetails, bool, is_fake, false);
};
};
struct FrameworkEnvironment {
- FrameworkEnvironment(DebugMode debug_mode = DebugMode::none) noexcept;
+ FrameworkEnvironment(DebugMode debug_mode = DebugMode::none, bool override_icds = false, bool override_layers = false) noexcept;
void add_icd(TestICDDetails icd_details) noexcept;
void add_implicit_layer(ManifestLayer layer_manifest, const std::string& json_name) noexcept;
std::vector<TestLayerHandle> layers;
std::string env_var_vk_icd_filenames;
+ std::string add_env_var_vk_icd_filenames;
private:
void add_layer_impl(TestLayerDetails layer_details, fs::FolderManager& folder_manager, ManifestCategory category);
--- /dev/null
+/*
+ * Copyright (c) 2021-2022 The Khronos Group Inc.
+ * Copyright (c) 2021-2022 Valve Corporation
+ * Copyright (c) 2021-2022 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and/or associated documentation files (the "Materials"), to
+ * deal in the Materials without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Materials, and to permit persons to whom the Materials are
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included in
+ * all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ *
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+ * USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ * Author: Charles Giessen <charles@lunarg.com>
+ * Author: Mark Young <markylunarg.com>
+ */
+
+#include "test_environment.h"
+
+class EnvVarICDOverrideSetup : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ remove_env_var("VK_ICD_FILENAMES");
+ remove_env_var("VK_DRIVER_FILES");
+ remove_env_var("VK_ADD_DRIVER_FILES");
+ }
+
+ virtual void TearDown() {
+ remove_env_var("VK_ICD_FILENAMES");
+ remove_env_var("VK_DRIVER_FILES");
+ remove_env_var("VK_ADD_DRIVER_FILES");
+ }
+};
+
+// Don't support vk_icdNegotiateLoaderICDInterfaceVersion
+// Loader calls vk_icdGetInstanceProcAddr second
+// does not support vk_icdGetInstanceProcAddr
+// must export vkGetInstanceProcAddr, vkCreateInstance, vkEnumerateInstanceExtensionProperties
+TEST(EnvVarICDOverrideSetup, version_0_none) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_env_var_icd_filenames(true));
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.CheckCreate();
+
+ ASSERT_EQ(env.get_test_icd(0).called_vk_icd_gipa, CalledICDGIPA::vk_gipa);
+}
+
+// Don't support vk_icdNegotiateLoaderICDInterfaceVersion
+// the loader calls vk_icdGetInstanceProcAddr first
+TEST(EnvVarICDOverrideSetup, version_1_icd_gipa) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_ICD_GIPA).set_use_env_var_icd_filenames(true));
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.CheckCreate();
+
+ ASSERT_EQ(env.get_test_icd(0).called_vk_icd_gipa, CalledICDGIPA::vk_icd_gipa);
+}
+
+// support vk_icdNegotiateLoaderICDInterfaceVersion but not vk_icdGetInstanceProcAddr
+// should assert that `interface_vers == 0` due to version mismatch, only checkable in Debug Mode
+TEST(EnvVarICDOverrideSetup, version_negotiate_interface_version_death_test) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NEGOTIATE_INTERFACE_VERSION).set_use_env_var_icd_filenames(true));
+
+ InstWrapper inst{env.vulkan_functions};
+
+#if !defined(NDEBUG)
+#if defined(WIN32)
+ ASSERT_DEATH(inst.CheckCreate(), "");
+#else
+ ASSERT_DEATH(inst.CheckCreate(), "interface_vers == 0");
+#endif
+#else
+ inst.CheckCreate();
+#endif
+}
+
+// export vk_icdNegotiateLoaderICDInterfaceVersion and vk_icdGetInstanceProcAddr
+TEST(EnvVarICDOverrideSetup, version_2_negotiate_interface_version_and_icd_gipa) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2).set_use_env_var_icd_filenames(true));
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.CheckCreate();
+
+ ASSERT_EQ(env.get_test_icd(0).called_vk_icd_gipa, CalledICDGIPA::vk_icd_gipa);
+}
+
+// Test VK_DRIVER_FILES environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyDriverEnvVar) {
+ FrameworkEnvironment env{DebugMode::none, true};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_env_var_icd_filenames(true));
+ env.get_test_icd(0).physical_devices.emplace_back("pd0");
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+ EXPECT_FALSE(
+ env.debug_log.find("Ignoring override VK_ICD_FILENAMES, VK_DRIVER_FILES, and VK_ADD_DRIVER_FILES due to high-integrity"));
+
+ std::array<VkPhysicalDevice, 5> phys_devs_array;
+ uint32_t phys_dev_count = 1;
+ ASSERT_EQ(inst1->vkEnumeratePhysicalDevices(inst1.inst, &phys_dev_count, phys_devs_array.data()), VK_SUCCESS);
+ ASSERT_EQ(phys_dev_count, 1);
+
+ for (uint32_t add = 0; add < 2; ++add) {
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_env_var_icd_filenames(true));
+ env.get_test_icd(add + 1).physical_devices.emplace_back("pd" + std::to_string(add) + "0");
+ env.get_test_icd(add + 1).physical_devices.emplace_back("pd" + std::to_string(add) + "1");
+ }
+
+ env.debug_log.clear();
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate();
+
+ phys_dev_count = 5;
+ ASSERT_EQ(inst2->vkEnumeratePhysicalDevices(inst2.inst, &phys_dev_count, phys_devs_array.data()), VK_SUCCESS);
+ ASSERT_EQ(phys_dev_count, 5);
+
+ env.debug_log.clear();
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst3{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst3.create_info, env.debug_log);
+ inst3.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+
+ EXPECT_TRUE(env.debug_log.find("vkCreateInstance: Found no drivers!"));
+
+ env.platform_shim->set_elevated_privilege(false);
+
+ remove_env_var("VK_DRIVER_FILES");
+}
+
+#if defined(__linux__) || defined(__FreeBSD__)
+// Make sure the loader reports the correct message based on if USE_UNSAFE_FILE_SEARCH is set or not
+TEST(EnvVarICDOverrideSetup, NonSecureEnvVarLookup) {
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+ env.get_test_icd().physical_devices.emplace_back("physical_device_0");
+
+ DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, log);
+ inst.CheckCreate();
+
+#if !defined(USE_UNSAFE_FILE_SEARCH)
+ ASSERT_FALSE(log.find("Loader is using non-secure environment variable lookup for"));
+#else
+ ASSERT_TRUE(log.find("Loader is using non-secure environment variable lookup for"));
+#endif
+}
+
+// Check for proper handling of paths specified via environment variables.
+TEST(EnvVarICDOverrideSetup, XDG) {
+ // Set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ fs::path HOME = "/home/fake_home";
+ set_env_var("HOME", HOME.str());
+ set_env_var("XDG_CONFIG_DIRS", ":/tmp/goober:::::/tmp/goober/::::");
+ set_env_var("XDG_CONFIG_HOME", ":/tmp/goober:::::/tmp/goober2/::::");
+ set_env_var("XDG_DATA_DIRS", "::::/tmp/goober3:/tmp/goober4/with spaces:::");
+ set_env_var("XDG_DATA_HOME", "::::/tmp/goober3:/tmp/goober4/with spaces:::");
+
+ FrameworkEnvironment env{};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+ env.get_test_icd().physical_devices.push_back({});
+
+ InstWrapper inst{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
+ inst.CheckCreate();
+
+ auto check_paths = [](DebugUtilsLogger const& debug_log, ManifestCategory category, fs::path const& HOME) {
+ EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober/vulkan") / category_path_name(category)).str()));
+ EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober2/vulkan") / category_path_name(category)).str()));
+ EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober3/vulkan") / category_path_name(category)).str()));
+ EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober4/with spaces/vulkan") / category_path_name(category)).str()));
+ };
+ check_paths(env.debug_log, ManifestCategory::icd, HOME);
+ check_paths(env.debug_log, ManifestCategory::implicit_layer, HOME);
+ check_paths(env.debug_log, ManifestCategory::explicit_layer, HOME);
+}
+#endif
+
+// Test VK_ADD_DRIVER_FILES environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyAddDriverEnvVar) {
+ FrameworkEnvironment env{DebugMode::none, true};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_add_env_var_icd_filenames(true));
+ env.get_test_icd(0).physical_devices.emplace_back("pd0");
+
+ InstWrapper inst1{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ std::array<VkPhysicalDevice, 1> phys_devs_array;
+ uint32_t phys_dev_count = 1;
+ ASSERT_EQ(inst1->vkEnumeratePhysicalDevices(inst1.inst, &phys_dev_count, phys_devs_array.data()), VK_SUCCESS);
+ ASSERT_EQ(phys_dev_count, 1);
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst2{env.vulkan_functions};
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
+
+ EXPECT_TRUE(env.debug_log.find("vkCreateInstance: Found no drivers!"));
+
+ env.platform_shim->set_elevated_privilege(false);
+
+ remove_env_var("VK_ADD_DRIVER_FILES");
+}
+
+// Test Both VK_DRIVER_FILES and VK_ADD_DRIVER_FILES environment variable
+TEST(EnvVarICDOverrideSetup, TestBothDriverEnvVars) {
+ FrameworkEnvironment env{DebugMode::none, true};
+
+ // Add a driver that isn't enabled with the environment variable
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_env_var_icd_filenames(true));
+ env.get_test_icd(0).physical_devices.emplace_back("pd0");
+ env.get_test_icd(0).physical_devices.emplace_back("pd1");
+
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_add_env_var_icd_filenames(true));
+ env.get_test_icd(0).physical_devices.emplace_back("pd2");
+
+ InstWrapper inst{env.vulkan_functions};
+ inst.CheckCreate();
+
+ // The enumerate should now detect both drivers because we used the add
+ std::array<VkPhysicalDevice, 3> phys_devs_array;
+ uint32_t phys_dev_count = 3;
+ ASSERT_EQ(inst->vkEnumeratePhysicalDevices(inst.inst, &phys_dev_count, phys_devs_array.data()), VK_SUCCESS);
+ ASSERT_EQ(phys_dev_count, 3);
+
+ remove_env_var("VK_DRIVER_FILES");
+ remove_env_var("VK_ADD_DRIVER_FILES");
+}
+
+#if defined(__linux__) || defined(__FreeBSD__)
+// Test VK_LAYER_PATH environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyLayerEnvVar) {
+ // Set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ fs::path HOME = "/home/fake_home";
+ set_env_var("HOME", HOME.str());
+ std::string vk_layer_path = ":/tmp/carol::::/:";
+ vk_layer_path += (HOME / "/ with spaces/:::::/tandy:").str();
+ set_env_var("VK_LAYER_PATH", vk_layer_path);
+
+ FrameworkEnvironment env{DebugMode::none, false, true};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+ env.get_test_icd().physical_devices.push_back({});
+ env.platform_shim->redirect_path("/tmp/carol", env.explicit_layer_folder.location());
+
+ const char* layer_name = "TestLayer";
+ env.add_explicit_layer(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "test_layer.json");
+
+ InstWrapper inst1{env.vulkan_functions};
+ inst1.create_info.add_layer(layer_name);
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ // look for VK_LAYER_PATHS
+ EXPECT_TRUE(env.debug_log.find("/tmp/carol"));
+ EXPECT_TRUE(env.debug_log.find("/tandy"));
+ EXPECT_TRUE(env.debug_log.find((HOME / "/ with spaces/").str()));
+
+ env.debug_log.clear();
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst2{env.vulkan_functions};
+ inst2.create_info.add_layer(layer_name);
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+ EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
+
+ env.platform_shim->set_elevated_privilege(false);
+
+ remove_env_var("VK_LAYER_PATH");
+}
+
+// Test VK_ADD_LAYER_PATH environment variable
+TEST(EnvVarICDOverrideSetup, TestOnlyAddLayerEnvVar) {
+ // Set up a layer path that includes default and user-specified locations,
+ // so that the test app can find them. Include some badly specified elements as well.
+ // Need to redirect the 'home' directory
+ fs::path HOME = "/home/fake_home";
+ set_env_var("HOME", HOME.str());
+ std::string vk_layer_path = ":/tmp/carol::::/:";
+ vk_layer_path += (HOME / "/ with spaces/:::::/tandy:").str();
+ set_env_var("VK_ADD_LAYER_PATH", vk_layer_path);
+
+ FrameworkEnvironment env{DebugMode::none, false, true};
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
+ env.get_test_icd().physical_devices.push_back({});
+ env.platform_shim->redirect_path("/tmp/carol", env.explicit_layer_folder.location());
+
+ const char* layer_name = "TestLayer";
+ env.add_explicit_layer(
+ ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
+ "test_layer.json");
+
+ InstWrapper inst1{env.vulkan_functions};
+ inst1.create_info.add_layer(layer_name);
+ FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
+ inst1.CheckCreate();
+
+ // look for VK_ADD_LAYER_PATHS
+ EXPECT_TRUE(env.debug_log.find("/tmp/carol"));
+ EXPECT_TRUE(env.debug_log.find("/tandy"));
+ EXPECT_TRUE(env.debug_log.find((HOME / "/ with spaces/").str()));
+
+ env.debug_log.clear();
+
+ env.platform_shim->set_elevated_privilege(true);
+
+ InstWrapper inst2{env.vulkan_functions};
+ inst2.create_info.add_layer(layer_name);
+ FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
+ inst2.CheckCreate(VK_ERROR_LAYER_NOT_PRESENT);
+
+ EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
+
+ env.platform_shim->set_elevated_privilege(false);
+
+ remove_env_var("VK_ADD_LAYER_PATH");
+}
+
+#endif
}
}
-#if defined(__linux__) || defined(__FreeBSD__)
-// Make sure the loader reports the correct message based on if USE_UNSAFE_FILE_SEARCH is set or not
-TEST(EnvironmentVariables, NonSecureEnvVarLookup) {
- FrameworkEnvironment env{};
- env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
- env.get_test_icd().physical_devices.emplace_back("physical_device_0");
-
- DebugUtilsLogger log{VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT};
- InstWrapper inst{env.vulkan_functions};
- FillDebugUtilsCreateDetails(inst.create_info, log);
- inst.CheckCreate();
-
-#if !defined(USE_UNSAFE_FILE_SEARCH)
- ASSERT_FALSE(log.find("Loader is using non-secure environment variable lookup for"));
-#else
- ASSERT_TRUE(log.find("Loader is using non-secure environment variable lookup for"));
-#endif
-}
-
-// Check for proper handling of paths specified via environment variables.
-TEST(EnvironmentVariables, XDG) {
- // Set up a layer path that includes default and user-specified locations,
- // so that the test app can find them. Include some badly specified elements as well.
- // Need to redirect the 'home' directory
- fs::path HOME = "/home/fake_home";
- set_env_var("HOME", HOME.str());
- set_env_var("XDG_CONFIG_DIRS", ":/tmp/goober:::::/tmp/goober/::::");
- set_env_var("XDG_CONFIG_HOME", ":/tmp/goober:::::/tmp/goober2/::::");
- set_env_var("XDG_DATA_DIRS", "::::/tmp/goober3:/tmp/goober4/with spaces:::");
- set_env_var("XDG_DATA_HOME", "::::/tmp/goober3:/tmp/goober4/with spaces:::");
-
- FrameworkEnvironment env{};
- env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
- env.get_test_icd().physical_devices.push_back({});
-
- InstWrapper inst{env.vulkan_functions};
- FillDebugUtilsCreateDetails(inst.create_info, env.debug_log);
- inst.CheckCreate();
-
- auto check_paths = [](DebugUtilsLogger const& debug_log, ManifestCategory category, fs::path const& HOME) {
- EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober/vulkan") / category_path_name(category)).str()));
- EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober2/vulkan") / category_path_name(category)).str()));
- EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober3/vulkan") / category_path_name(category)).str()));
- EXPECT_TRUE(debug_log.find((fs::path("/tmp/goober4/with spaces/vulkan") / category_path_name(category)).str()));
- };
- check_paths(env.debug_log, ManifestCategory::icd, HOME);
- check_paths(env.debug_log, ManifestCategory::implicit_layer, HOME);
- check_paths(env.debug_log, ManifestCategory::explicit_layer, HOME);
-}
-
-// Check for proper handling of paths specified via environment variables.
-TEST(EnvironmentVariables, VK_LAYER_PATH) {
- // Set up a layer path that includes default and user-specified locations,
- // so that the test app can find them. Include some badly specified elements as well.
- // Need to redirect the 'home' directory
- fs::path HOME = "/home/fake_home";
- set_env_var("HOME", HOME.str());
- std::string vk_layer_path = ":/tmp/carol::::/:";
- vk_layer_path += (HOME / "/ with spaces/:::::/tandy:").str();
- set_env_var("VK_LAYER_PATH", vk_layer_path);
-
- FrameworkEnvironment env{};
- env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_6));
- env.get_test_icd().physical_devices.push_back({});
- env.platform_shim->redirect_path("/tmp/carol", env.explicit_layer_folder.location());
-
- const char* layer_name = "TestLayer";
- env.add_explicit_layer(
- ManifestLayer{}.add_layer(
- ManifestLayer::LayerDescription{}.set_name(layer_name).set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)),
- "test_layer.json");
-
- InstWrapper inst1{env.vulkan_functions};
- inst1.create_info.add_layer(layer_name);
- FillDebugUtilsCreateDetails(inst1.create_info, env.debug_log);
- inst1.CheckCreate();
-
- // look for VK_LAYER_PATHS
- EXPECT_TRUE(env.debug_log.find("/tmp/carol"));
- EXPECT_TRUE(env.debug_log.find("/tandy"));
- EXPECT_TRUE(env.debug_log.find((HOME / "/ with spaces/").str()));
-
- env.debug_log.clear();
-
- env.platform_shim->set_elevated_privilege(true);
-
- InstWrapper inst2{env.vulkan_functions};
- inst2.create_info.add_layer(layer_name);
- FillDebugUtilsCreateDetails(inst2.create_info, env.debug_log);
- inst2.CheckCreate();
-
- EXPECT_FALSE(env.debug_log.find("/tmp/carol"));
-
- env.platform_shim->set_elevated_privilege(false);
-
- remove_env_var("VK_LAYER_PATH");
-}
-#endif
-
TEST(ExtensionManual, ToolingProperties) {
VkPhysicalDeviceToolPropertiesEXT icd_tool_props{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT,
nullptr,
// make sure the tests don't find these env-vars if they were set on the system
remove_env_var("VK_ICD_FILENAMES");
+ remove_env_var("VK_DRIVER_FILES");
+ remove_env_var("VK_ADD_DRIVER_FILES");
remove_env_var("VK_LAYER_PATH");
+ remove_env_var("VK_ADD_LAYER_PATH");
remove_env_var("VK_INSTANCE_LAYERS");
remove_env_var("VK_LOADER_DEBUG");
remove_env_var("VK_LOADER_DISABLE_INST_EXT_FILTER");
#include "test_environment.h"
-class EnvVarICDOverrideSetup : public ::testing::Test {
- protected:
- virtual void SetUp() { env = std::unique_ptr<FrameworkEnvironment>(new FrameworkEnvironment()); }
-
- virtual void TearDown() {
- remove_env_var("VK_ICD_FILENAMES");
- env.reset();
- }
- std::unique_ptr<FrameworkEnvironment> env;
-};
-
-// Don't support vk_icdNegotiateLoaderICDInterfaceVersion
-// Loader calls vk_icdGetInstanceProcAddr second
-// does not support vk_icdGetInstanceProcAddr
-// must export vkGetInstanceProcAddr, vkCreateInstance, vkEnumerateInstanceExtensionProperties
-TEST_F(EnvVarICDOverrideSetup, version_0_none) {
- env->add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NONE).set_use_env_var_icd_filenames(true));
- auto& driver = env->reset_icd();
-
- InstWrapper inst{env->vulkan_functions};
- inst.CheckCreate();
-
- ASSERT_EQ(driver.called_vk_icd_gipa, CalledICDGIPA::vk_gipa);
-}
-
-// Don't support vk_icdNegotiateLoaderICDInterfaceVersion
-// the loader calls vk_icdGetInstanceProcAddr first
-TEST_F(EnvVarICDOverrideSetup, version_1_icd_gipa) {
- env->add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_ICD_GIPA).set_use_env_var_icd_filenames(true));
- auto& driver = env->reset_icd();
-
- InstWrapper inst{env->vulkan_functions};
- inst.CheckCreate();
-
- ASSERT_EQ(driver.called_vk_icd_gipa, CalledICDGIPA::vk_icd_gipa);
-}
-
-// support vk_icdNegotiateLoaderICDInterfaceVersion but not vk_icdGetInstanceProcAddr
-// should assert that `interface_vers == 0` due to version mismatch, only checkable in Debug Mode
-TEST_F(EnvVarICDOverrideSetup, version_negotiate_interface_version_death_test) {
- env->add_icd(TestICDDetails(TEST_ICD_PATH_EXPORT_NEGOTIATE_INTERFACE_VERSION).set_use_env_var_icd_filenames(true));
- env->reset_icd();
-
- InstWrapper inst{env->vulkan_functions};
-
-#if !defined(NDEBUG)
-#if defined(WIN32)
- ASSERT_DEATH(inst.CheckCreate(), "");
-#else
- ASSERT_DEATH(inst.CheckCreate(), "interface_vers == 0");
-#endif
-#else
- inst.CheckCreate();
-#endif
-}
-
-// export vk_icdNegotiateLoaderICDInterfaceVersion and vk_icdGetInstanceProcAddr
-TEST_F(EnvVarICDOverrideSetup, version_2_negotiate_interface_version_and_icd_gipa) {
- env->add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2).set_use_env_var_icd_filenames(true));
- auto& driver = env->reset_icd();
-
- InstWrapper inst{env->vulkan_functions};
- inst.CheckCreate();
-
- ASSERT_EQ(driver.called_vk_icd_gipa, CalledICDGIPA::vk_icd_gipa);
-}
-
class ICDInterfaceVersion2Plus : public ::testing::Test {
protected:
virtual void SetUp() {