From: Mark Young Date: Tue, 4 Jan 2022 18:45:18 +0000 (-0700) Subject: Add "additive" environment variables X-Git-Tag: upstream/v1.3.207~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=46abc7dc4eafeee16e9306e555a330b2a414268a;p=platform%2Fupstream%2FVulkan-Loader.git Add "additive" environment variables Add "additive" environment variables for adding additional layer paths or driver JSON files instead of replacing default ones. Also, rename VK_ICD_FILENAMES to VK_DRIVER_FILES since we're trying to remove references to ICDs because software driver implementations of Vulkan aren't ICDs (but continue to support the old name as well). Added documentation around these changes to reflect the new name and the new variables. --- diff --git a/BUILD.md b/BUILD.md index 45972f4d..215c4f0a 100644 --- a/BUILD.md +++ b/BUILD.md @@ -721,7 +721,7 @@ Before you run these tests, you will need to clone and build the You will also need to direct your new loader to the MoltenVK ICD: - export VK_ICD_FILENAMES=/Package/Latest/MoltenVK/macOS/MoltenVK_icd.json + export VK_DRIVER_FILES=/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: diff --git a/docs/LoaderDriverInterface.md b/docs/LoaderDriverInterface.md index 7576822b..4999a06f 100644 --- a/docs/LoaderDriverInterface.md +++ b/docs/LoaderDriverInterface.md @@ -99,22 +99,37 @@ Driver. 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) @@ -132,28 +147,44 @@ For example: ##### 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. @@ -348,7 +379,7 @@ See the [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 @@ -439,11 +470,11 @@ developer's build tree. 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 @@ -1614,8 +1645,9 @@ Android Vulkan documentation. LDP_LOADER_13 A loader must not load from user-defined paths (including the - use of the VK_ICD_FILENAMES environment variable) when running - elevated (Administrator/Super-user) applications.
+ use of any of VK_ICD_FILENAMES, VK_DRIVER_FILES, or + VK_ADD_DRIVER_FILES environment variables) when running elevated + (Administrator/Super-user) applications.
This is for security reasons. The behavior is undefined and may result in computer security lapses, diff --git a/docs/LoaderInterfaceArchitecture.md b/docs/LoaderInterfaceArchitecture.md index 1db838df..73a50e40 100644 --- a/docs/LoaderInterfaceArchitecture.md +++ b/docs/LoaderInterfaceArchitecture.md @@ -417,8 +417,10 @@ using untrusted results. 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) @@ -491,8 +493,11 @@ discovery. Example Format - VK_ICD_FILENAMES - Force the loader to use the specific ICD JSON files. + VK_ADD_DRIVER_FILES + 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.
NOTE: If a global path to the JSON file is not used, issues @@ -503,11 +508,57 @@ discovery. for more information. export
-   VK_ICD_FILENAMES=
+   VK_ADD_DRIVER_FILES=
     /intel.json:/amd.json

set
-   VK_ICD_FILENAMES=
+   VK_ADD_DRIVER_FILES=
+      \nvidia.json;\mesa.json +
+ + + + VK_ADD_LAYER_PATH + 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. +
+ Ignored when running Vulkan application in executing with + elevated privileges. + See Elevated Privilege Caveats + for more information. + + export
+   VK_ADD_LAYER_PATH=
+      <path_a>;<path_b>

+ set
+   VK_ADD_LAYER_PATH=
+      <path_a>;<path_b>
+ + + + VK_DRIVER_FILES + 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.
+ This has replaced the older deprecated environment variable + VK_ICD_FILENAMES, however the older environment variable will + continue to work for some time. + NOTE: If a global path to the JSON file is not used, issues + may be encountered.
+ Ignored when running Vulkan application in executing with + elevated privileges. + See Elevated Privilege Caveats + for more information. + + export
+   VK_DRIVER_FILES=
+      /intel.json:/amd.json +

+ set
+   VK_DRIVER_FILES=
     \nvidia.json;\mesa.json
@@ -565,7 +616,6 @@ discovery. loader before returning the set of physical devices to layers.
set VK_LOADER_DISABLE_SELECT=1 - VK_LOADER_DISABLE_INST_EXT_FILTER diff --git a/docs/LoaderLayerInterface.md b/docs/LoaderLayerInterface.md index 2f2a4097..48b0ee1b 100644 --- a/docs/LoaderLayerInterface.md +++ b/docs/LoaderLayerInterface.md @@ -231,8 +231,14 @@ 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 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. @@ -317,10 +323,16 @@ manifest files: 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. @@ -333,9 +345,10 @@ See 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 @@ -397,11 +410,12 @@ following: ### 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) @@ -2409,8 +2423,9 @@ Android Vulkan documentation. LLP_LOADER_13 A loader must not load from user-defined paths (including the - use of the VK_LAYER_PATH environment variable) when running - elevated (Administrator/Super-user) applications.
+ use of either VK_LAYER_PATH or VK_ADD_LAYER_PATH + environment variables) when running elevated (Administrator/Super-user) + applications.
This is for security reasons. The behavior is undefined and may result in computer security lapses, diff --git a/loader/loader.c b/loader/loader.c index 1adb03c8..4452710e 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -119,6 +119,13 @@ int loader_closedir(const struct loader_instance *instance, DIR *dir) { #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) { @@ -2674,7 +2681,7 @@ static inline size_t determine_data_file_path_size(const char *cur_path, size_t 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; @@ -2694,15 +2701,20 @@ static inline void copy_data_file_path(const char *cur_path, const char *relativ 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; } @@ -2773,7 +2785,7 @@ static VkResult add_if_manifest_file(const struct loader_instance *inst, const c // 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; @@ -2786,8 +2798,10 @@ 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; @@ -2806,38 +2820,9 @@ VkResult add_data_files_in_path(const struct loader_instance *inst, char *search 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 @@ -2849,7 +2834,7 @@ VkResult add_data_files_in_path(const struct loader_instance *inst, char *search 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); @@ -2868,6 +2853,36 @@ VkResult add_data_files_in_path(const struct loader_instance *inst, char *search 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; @@ -2881,14 +2896,15 @@ out: // 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; @@ -2937,6 +2953,8 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in 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); @@ -2964,17 +2982,43 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in 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; } @@ -2984,45 +3028,49 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in // 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 @@ -3040,7 +3088,22 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in // 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__) @@ -3057,7 +3120,7 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in 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; } } @@ -3065,29 +3128,22 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in } } #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 @@ -3138,7 +3194,7 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in 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 { @@ -3158,7 +3214,7 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in } // 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:"); @@ -3177,6 +3233,9 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in out: + if (NULL != additional_env) { + loader_free_getenv(additional_env, inst); + } if (NULL != override_env) { loader_free_getenv(override_env, inst); } @@ -3216,15 +3275,12 @@ out: // 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 @@ -3239,9 +3295,9 @@ out: // 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; @@ -3259,8 +3315,7 @@ VkResult loader_get_data_files(const struct loader_instance *inst, enum loader_d 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; } @@ -3268,8 +3323,32 @@ VkResult loader_get_data_files(const struct loader_instance *inst, enum loader_d #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; } } @@ -3296,10 +3375,10 @@ void loader_destroy_icd_lib_list() {} // 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 @@ -3320,8 +3399,7 @@ VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_t 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; } @@ -3568,9 +3646,7 @@ void loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_li 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; } @@ -3618,7 +3694,7 @@ void loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_li } 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; @@ -3630,8 +3706,7 @@ void loader_scan_for_layers(struct loader_instance *inst, struct loader_layer_li } // 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; } @@ -3703,9 +3778,7 @@ void loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader // 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; } @@ -3762,7 +3835,7 @@ void loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader } 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; @@ -3780,8 +3853,7 @@ void loader_scan_for_implicit_layers(struct loader_instance *inst, struct loader // 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; } @@ -5695,6 +5767,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateI // 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; } diff --git a/loader/loader.h b/loader/loader.h index 4ef69966..51c5aae9 100644 --- a/loader/loader.h +++ b/loader/loader.h @@ -169,5 +169,5 @@ VkResult setup_loader_tramp_phys_dev_groups(struct loader_instance *inst, uint32 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); diff --git a/loader/loader_common.h b/loader/loader_common.h index 3b8c7c00..e0039388 100644 --- a/loader/loader_common.h +++ b/loader/loader_common.h @@ -31,6 +31,12 @@ #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 @@ -445,7 +451,7 @@ struct loader_scanned_icd { }; 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 }; diff --git a/loader/loader_windows.c b/loader/loader_windows.c index a16019bd..7aa730e4 100644 --- a/loader/loader_windows.c +++ b/loader/loader_windows.c @@ -168,7 +168,7 @@ bool windows_get_device_registry_entry(const struct loader_instance *inst, char 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; @@ -179,18 +179,19 @@ bool windows_get_device_registry_entry(const struct loader_instance *inst, char 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; } @@ -198,14 +199,14 @@ bool windows_get_device_registry_entry(const struct loader_instance *inst, char 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; @@ -221,8 +222,8 @@ 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 @@ -252,7 +253,7 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c 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; @@ -263,25 +264,26 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c 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; @@ -292,7 +294,7 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c 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; } @@ -301,12 +303,12 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c 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; @@ -314,7 +316,7 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c } 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; } @@ -331,6 +333,7 @@ VkResult windows_get_device_registry_files(const struct loader_instance *inst, c } 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; } @@ -395,13 +398,14 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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"); @@ -421,7 +425,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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; @@ -433,7 +437,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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); @@ -446,7 +450,8 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo // 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) { @@ -457,7 +462,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo } } 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; @@ -467,7 +472,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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; @@ -477,7 +482,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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; @@ -490,7 +495,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo } 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; } @@ -523,7 +528,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo 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); @@ -544,6 +549,7 @@ VkResult windows_get_registry_files(const struct loader_instance *inst, char *lo } 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; } @@ -693,11 +699,14 @@ VkResult windows_read_data_files_in_registry(const struct loader_instance *inst, 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. @@ -707,17 +716,20 @@ VkResult windows_read_data_files_in_registry(const struct loader_instance *inst, // 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()); } } @@ -735,8 +747,8 @@ VkResult windows_read_data_files_in_registry(const struct loader_instance *inst, } 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; @@ -744,11 +756,11 @@ VkResult windows_read_data_files_in_registry(const struct loader_instance *inst, 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."); } } @@ -759,7 +771,7 @@ VkResult windows_read_data_files_in_registry(const struct loader_instance *inst, } // 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: diff --git a/loader/loader_windows.h b/loader/loader_windows.h index a02151b0..95ce645f 100644 --- a/loader/loader_windows.h +++ b/loader/loader_windows.h @@ -70,8 +70,8 @@ bool windows_get_device_registry_entry(const struct loader_instance *inst, char // // *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". // diff --git a/loader/trampoline.c b/loader/trampoline.c index 4d744a31..48abb962 100644 --- a/loader/trampoline.c +++ b/loader/trampoline.c @@ -550,11 +550,13 @@ LOADER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCr 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; diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index 4c7f0f2a..bda77eb2 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h @@ -1,8 +1,8 @@ /* * - * 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. @@ -96,8 +96,11 @@ #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" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 12d108bc..1c06c71f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,6 +29,7 @@ add_executable( 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 diff --git a/tests/framework/README.md b/tests/framework/README.md index 5267a5a2..6002258f 100644 --- a/tests/framework/README.md +++ b/tests/framework/README.md @@ -191,4 +191,4 @@ drivers and layers that are in the environment, allowing quick modification of t 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. diff --git a/tests/framework/layer/wrap_objects.cpp b/tests/framework/layer/wrap_objects.cpp index f78fab1a..3377af23 100644 --- a/tests/framework/layer/wrap_objects.cpp +++ b/tests/framework/layer/wrap_objects.cpp @@ -429,7 +429,7 @@ VKAPI_ATTR VkResult VKAPI_CALL wrap_vkEnumerateDeviceExtensionProperties(VkPhysi 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++; @@ -442,7 +442,8 @@ VKAPI_ATTR VkResult VKAPI_CALL wrap_vkEnumerateDeviceExtensionProperties(VkPhysi 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++; @@ -598,7 +599,7 @@ PFN_vkVoidFunction layer_intercept_instance_proc(wrapped_inst_obj *inst, const c #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; diff --git a/tests/framework/test_environment.cpp b/tests/framework/test_environment.cpp index 5d5f2ad3..e2b80fa7 100644 --- a/tests/framework/test_environment.cpp +++ b/tests/framework/test_environment.cpp @@ -182,7 +182,7 @@ TestLayer& TestLayerHandle::reset_layer() noexcept { } 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), @@ -191,8 +191,16 @@ FrameworkEnvironment::FrameworkEnvironment(DebugMode debug_mode) noexcept 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()); } @@ -221,7 +229,13 @@ void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept { 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); } diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h index e304d347..2cf228fb 100644 --- a/tests/framework/test_environment.h +++ b/tests/framework/test_environment.h @@ -308,6 +308,7 @@ struct TestICDDetails { 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); }; @@ -322,7 +323,7 @@ struct TestLayerDetails { }; 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; @@ -352,6 +353,7 @@ struct FrameworkEnvironment { std::vector 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); diff --git a/tests/loader_envvar_tests.cpp b/tests/loader_envvar_tests.cpp new file mode 100644 index 00000000..7515bd43 --- /dev/null +++ b/tests/loader_envvar_tests.cpp @@ -0,0 +1,351 @@ +/* + * 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 + * Author: Mark Young + */ + +#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 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 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 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 diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp index c865e8bb..db6a5c52 100644 --- a/tests/loader_regression_tests.cpp +++ b/tests/loader_regression_tests.cpp @@ -2121,105 +2121,6 @@ TEST_F(EnumeratePhysicalDeviceGroups, FakePNext) { } } -#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, diff --git a/tests/loader_testing_main.cpp b/tests/loader_testing_main.cpp index a2aefd00..1ddfbfa4 100644 --- a/tests/loader_testing_main.cpp +++ b/tests/loader_testing_main.cpp @@ -50,7 +50,10 @@ int main(int argc, char** argv) { // 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"); diff --git a/tests/loader_version_tests.cpp b/tests/loader_version_tests.cpp index 27a86c45..8ef47abe 100644 --- a/tests/loader_version_tests.cpp +++ b/tests/loader_version_tests.cpp @@ -27,73 +27,6 @@ #include "test_environment.h" -class EnvVarICDOverrideSetup : public ::testing::Test { - protected: - virtual void SetUp() { env = std::unique_ptr(new FrameworkEnvironment()); } - - virtual void TearDown() { - remove_env_var("VK_ICD_FILENAMES"); - env.reset(); - } - std::unique_ptr 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() {