diff --git a/docs/LoaderDriverInterface.md b/docs/LoaderDriverInterface.md
index 791c64c1c..ad600fb4e 100644
--- a/docs/LoaderDriverInterface.md
+++ b/docs/LoaderDriverInterface.md
@@ -33,6 +33,7 @@
- [Example Linux Driver Search Path](#example-linux-driver-search-path)
- [Driver Discovery on Fuchsia](#driver-discovery-on-fuchsia)
- [Driver Discovery on macOS](#driver-discovery-on-macos)
+ - [Use App Bundled Drivers exclusively](#use-app-bundled-drivers-exclusively)
- [Example macOS Driver Search Path](#example-macos-driver-search-path)
- [Additional Settings For Driver Debugging](#additional-settings-for-driver-debugging)
- [Driver Discovery using the`VK_LUNARG_direct_driver_loading` extension](#driver-discovery-using-thevk_lunarg_direct_driver_loading-extension)
@@ -512,16 +513,14 @@ The order is similar to the search path on Linux with the exception that
the application's bundle resources are searched first:
`(bundle)/Contents/Resources/`.
-System installed drivers will be ignored if drivers are found inside of the app
-bundle.
-This is because there is not a standard mechanism in which to distinguish drivers
-that happen to be duplicates.
-For example, MoltenVK is commonly placed inside application bundles.
-If there exists a system installed MoltenVK, the loader will load both the app
-bundled and the system installed MoltenVK, leading to potential issues or crashes.
-Drivers found through environment variables, such as `VK_DRIVER_FILES`, will be
-used regardless of whether there are bundled drivers present or not.
+#### Use App Bundled Drivers exclusively
+By default, the Vulkan Loader searches various system and user paths
+for driver manifests. Defining the environment variable
+`VK_LOADER_SEARCH_ONLY_IN_BUNDLE` makes the Vulkan Loader only search
+for driver manifests in `(bundle)/Contents/Resources/`. This is
+intended for applications including drivers inside of the app bundle
+so that any drivers elsewhere on the system do not affect the app.
#### Example macOS Driver Search Path
diff --git a/docs/LoaderInterfaceArchitecture.md b/docs/LoaderInterfaceArchitecture.md
index b0b52c91d..e90e8b104 100644
--- a/docs/LoaderInterfaceArchitecture.md
+++ b/docs/LoaderInterfaceArchitecture.md
@@ -46,6 +46,7 @@
- [Globs](#globs)
- [Case-Insensitive](#case-insensitive)
- [Environment Variable Priority](#environment-variable-priority)
+ - [Multiple Filtering](#multiple-filtering)
- [Table of Debug Environment Variables](#table-of-debug-environment-variables)
- [Active Environment Variables](#active-environment-variables)
- [Deprecated Environment Variables](#deprecated-environment-variables)
@@ -1061,6 +1062,26 @@ discovery.
VK_LOADER_DRIVER_ID_FILTER=1-3:13
+
+ |
+ VK_LOADER_SEARCH_ONLY_IN_BUNDLE
+ |
+
+ Prevents searching for layer and driver manifests outside of the
+ Application Bundle. Meant to isolate applications shipping on macOS/iOS
+ in a bundle from using system installed layers and drivers.
+ |
+
+ macOS/iOS only
+ This functionality is only available with Loaders built with version
+ 1.4.359 of the Vulkan headers and later.
+ |
+
+ export
+ VK_LOADER_SEARCH_ONLY_IN_BUNDLE=1
+
+ |
+
diff --git a/docs/LoaderLayerInterface.md b/docs/LoaderLayerInterface.md
index ea175e132..c07b10afc 100644
--- a/docs/LoaderLayerInterface.md
+++ b/docs/LoaderLayerInterface.md
@@ -25,6 +25,7 @@
- [Fuchsia Layer Discovery](#fuchsia-layer-discovery)
- [macOS Layer Discovery](#macos-layer-discovery)
- [Example macOS Implicit Layer Search Path](#example-macos-implicit-layer-search-path)
+ - [Use App Bundled Layers exclusively](#use-app-bundled-layers-exclusively)
- [Layer Filtering](#layer-filtering)
- [Layer Enable Filtering](#layer-enable-filtering)
- [Layer Disable Filtering](#layer-disable-filtering)
@@ -453,6 +454,15 @@ following:
/usr/share/vulkan/implicit_layer.d
```
+#### Use App Bundled Layers exclusively
+
+By default, the Vulkan Loader searches various system and user paths
+for layer manifests. Defining the environment variable
+`VK_LOADER_SEARCH_ONLY_IN_BUNDLE` makes the Vulkan Loader only search
+for layer manifests in `(bundle)/Contents/Resources/`. This is
+intended for applications including layers inside of the app bundle
+so that any layers elsewhere on the system do not affect the app.
+
### Layer Filtering
**NOTE:** This functionality is only available with Loaders built with version
diff --git a/loader/loader.c b/loader/loader.c
index 2574d4f4d..e29184837 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -3501,6 +3501,7 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
#if defined(__APPLE__)
char *bundle_path = NULL;
+ char *search_only_in_bundle_env_var = loader_secure_getenv(VK_LOADER_SEARCH_ONLY_IN_BUNDLE_ENV_VAR, inst);
#endif
#if defined(_WIN32)
@@ -3656,6 +3657,8 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
}
}
#elif COMMON_UNIX_PLATFORMS
+ bool search_outside_of_bundle = true;
+
rel_size = strlen(relative_location);
if (rel_size > 0) {
#if defined(__APPLE__)
@@ -3714,41 +3717,46 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
CFRelease(ref);
}
}
-#endif // __APPLE__
- // Only add the home folders if not NULL
- if (NULL != home_config_dir) {
- vk_result = copy_data_file_info(inst, home_config_dir, relative_location, rel_size, &search_paths);
+ if (NULL != search_only_in_bundle_env_var) {
+ search_outside_of_bundle = false;
+ }
+#endif // __APPLE__
+ if (search_outside_of_bundle) {
+ // Only add the home folders if not NULL
+ if (NULL != home_config_dir) {
+ vk_result = copy_data_file_info(inst, home_config_dir, relative_location, rel_size, &search_paths);
+ if (VK_SUCCESS != vk_result) {
+ goto out;
+ }
+ }
+ vk_result = copy_data_file_info(inst, xdg_config_dirs, relative_location, rel_size, &search_paths);
+ if (VK_SUCCESS != vk_result) {
+ goto out;
+ }
+ vk_result = copy_data_file_info(inst, SYSCONFDIR, relative_location, rel_size, &search_paths);
if (VK_SUCCESS != vk_result) {
goto out;
}
- }
- vk_result = copy_data_file_info(inst, xdg_config_dirs, relative_location, rel_size, &search_paths);
- if (VK_SUCCESS != vk_result) {
- goto out;
- }
- vk_result = copy_data_file_info(inst, SYSCONFDIR, relative_location, rel_size, &search_paths);
- if (VK_SUCCESS != vk_result) {
- goto out;
- }
#if defined(EXTRASYSCONFDIR)
- vk_result = copy_data_file_info(inst, EXTRASYSCONFDIR, relative_location, rel_size, &search_paths);
- if (VK_SUCCESS != vk_result) {
- goto out;
- }
+ vk_result = copy_data_file_info(inst, EXTRASYSCONFDIR, relative_location, rel_size, &search_paths);
+ if (VK_SUCCESS != vk_result) {
+ goto out;
+ }
#endif
- // Only add the home folders if not NULL
- if (NULL != home_data_dir) {
- vk_result = copy_data_file_info(inst, home_data_dir, relative_location, rel_size, &search_paths);
+ // Only add the home folders if not NULL
+ if (NULL != home_data_dir) {
+ vk_result = copy_data_file_info(inst, home_data_dir, relative_location, rel_size, &search_paths);
+ if (VK_SUCCESS != vk_result) {
+ goto out;
+ }
+ }
+ vk_result = copy_data_file_info(inst, xdg_data_dirs, relative_location, rel_size, &search_paths);
if (VK_SUCCESS != vk_result) {
goto out;
}
}
- vk_result = copy_data_file_info(inst, xdg_data_dirs, relative_location, rel_size, &search_paths);
- if (VK_SUCCESS != vk_result) {
- goto out;
- }
}
#else
#warning read_data_files_in_search_paths unsupported platform
@@ -3799,6 +3807,7 @@ VkResult read_data_files_in_search_paths(const struct loader_instance *inst, enu
#elif COMMON_UNIX_PLATFORMS
#if defined(__APPLE__)
loader_instance_heap_free(inst, bundle_path);
+ loader_free_getenv(search_only_in_bundle_env_var, inst);
#endif
loader_free_getenv(xdg_config_home, inst);
loader_free_getenv(xdg_config_dirs, inst);
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h
index 983b820d1..9549017fd 100644
--- a/loader/vk_loader_platform.h
+++ b/loader/vk_loader_platform.h
@@ -134,6 +134,10 @@
#define VK_VENDOR_ID_FILTER_ENV_VAR "VK_LOADER_VENDOR_ID_FILTER"
#define VK_DRIVER_ID_FILTER_ENV_VAR "VK_LOADER_DRIVER_ID_FILTER"
+#if defined(__APPLE__)
+#define VK_LOADER_SEARCH_ONLY_IN_BUNDLE_ENV_VAR "VK_LOADER_SEARCH_ONLY_IN_BUNDLE"
+#endif
+
// Override layer information
#define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h
index fe164d401..26acc66f8 100644
--- a/tests/framework/test_environment.h
+++ b/tests/framework/test_environment.h
@@ -541,7 +541,9 @@ struct FrameworkEnvironment {
#if TESTING_COMMON_UNIX_PLATFORMS
EnvVarWrapper env_var_home{"HOME", "/home/fake_home"};
-#if !defined(__APPLE__)
+#if defined(__APPLE__)
+ EnvVarWrapper env_var_search_only_in_bundle{"VK_LOADER_SEARCH_ONLY_IN_BUNDLE"};
+#else
EnvVarWrapper env_var_xdg_config_home{"XDG_CONFIG_HOME"};
EnvVarWrapper env_var_xdg_config_dirs{"XDG_CONFIG_DIRS"};
EnvVarWrapper env_var_xdg_data_home{"XDG_DATA_HOME"};
diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp
index eb2196f49..667aae427 100644
--- a/tests/loader_regression_tests.cpp
+++ b/tests/loader_regression_tests.cpp
@@ -4478,6 +4478,37 @@ TEST(ManifestDiscovery, AppleBundles) {
ASSERT_EQ(test_physical_device_0.properties.deviceID, props.deviceID);
}
+// Add two drivers, one to the bundle and one to the system locations
+TEST(ManifestDiscovery, AppleBundlesWithSearchOnlyInBundleEnvVar) {
+ FrameworkEnvironment env{};
+ env.env_var_search_only_in_bundle.set_new_value("1");
+ env.setup_macos_bundle();
+ env.add_icd(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA,
+ ManifestOptions{}.set_discovery_type(ManifestDiscoveryType::macos_bundle));
+ auto& test_physical_device_0 = env.get_test_icd(0).add_and_get_physical_device({});
+ test_physical_device_0.properties.deviceID = 1337;
+ env.add_icd(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA);
+ auto& test_physical_device_1 = env.get_test_icd(1).add_and_get_physical_device({});
+ test_physical_device_1.properties.deviceID = 9999;
+
+ env.add_explicit_layer(
+ {}, ManifestLayer{}.add_layer(
+ ManifestLayer::LayerDescription{}.set_name("VK_LAYER_test").set_lib_path(TEST_LAYER_PATH_EXPORT_VERSION_2)));
+
+ InstWrapper inst{env.vulkan_functions};
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+ auto physical_devices = inst.GetPhysDevs();
+ ASSERT_EQ(1, physical_devices.size());
+
+ // should only get bundled driver and layer
+ VkPhysicalDeviceProperties props{};
+ inst->vkGetPhysicalDeviceProperties(physical_devices[0], &props);
+ ASSERT_EQ(test_physical_device_0.properties.deviceID, props.deviceID);
+
+ // No layers should be found
+ env.GetLayerProperties(0);
+}
+
// Add two drivers, one to the bundle and one using the driver env-var
TEST(ManifestDiscovery, AppleBundlesEnvVarActive) {
FrameworkEnvironment env{};