Allow basic tests to be written which exercise the bundle discovery and loading logic
in the loader. This allows testing whether drivers found in bundles disables searching
for drivers on the rest of the system.
This commit also inclues fixes for a half dozen non essential spelling mistakes.
bool loader_check_version_meets_required(loader_api_version required, loader_api_version version) {
// major version is satisfied
return (version.major > required.major) ||
- // major version is equal, minor version is patch version is gerater to minimum minor
+ // major version is equal, minor version is patch version is greater to minimum minor
(version.major == required.major && version.minor > required.minor) ||
// major and minor version are equal, patch version is greater or equal to minimum patch
(version.major == required.major && version.minor == required.minor && version.patch >= required.patch);
// Trampoline entrypoints are in this file for core Vulkan commands
-/* vkGetInstanceProcAddr: Get global level or instance level entrypoint addressess.
+/* vkGetInstanceProcAddr: Get global level or instance level entrypoint addresses.
* @param instance
* @param pName
* @return
*
* Note:
* Vulkan header updated 1.2.193 changed the behavior of vkGetInstanceProcAddr for global entrypoints. They used to always be
- * returned regardless of the value of the instance paramtere. The spec was amended in this version to only allow querying global
+ * returned regardless of the value of the instance parameter. The spec was amended in this version to only allow querying global
* level entrypoints with a NULL instance. However, as to not break old applications, the new behavior is only applied if the
* instance passed in is both valid and minor version is greater than 1.2, which was when this change in behavior occurred. Only
* instances with a newer version will get the new behavior.
const VkLayerDispatchTable *disp = loader_get_dispatch(commandBuffer);
if (NULL == disp) {
loader_log(NULL, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
- "vkCmdCopyImage: Invalid commandBuffer [VUID-vkCmdCopyImage-devcommandBufferice-parameter]");
+ "vkCmdCopyImage: Invalid commandBuffer [VUID-vkCmdCopyImage-commandBuffer-parameter]");
abort(); /* Intentionally fail so user can correct issue. */
}
elseif(UNIX)
if(APPLE)
add_library(shim-library SHARED unix_shim.cpp)
+ target_link_libraries(shim-library PRIVATE "-framework CoreFoundation")
else()
add_library(shim-library STATIC unix_shim.cpp)
endif()
bool use_fake_elevation = false;
std::vector<DirEntry> dir_entries;
+
+ #if defined(__APPLE__)
+ std::string bundle_contents;
+ #endif
#endif
};
paths.push_back((home / ".config").str());
paths.push_back((home / ".local/share").str());
}
- parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_DIRS"));
- parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_HOME"));
- parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_DIRS"));
- parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_HOME"));
+ // Don't report errors on apple - these env-vars are not suppose to be defined
+ bool report_errors = true;
+#if defined(__APPLE__)
+ report_errors = false;
+#endif
+ parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_DIRS", report_errors));
+ parse_and_add_env_var_override(paths, get_env_var("XDG_CONFIG_HOME", report_errors));
+ parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_DIRS", report_errors));
+ parse_and_add_env_var_override(paths, get_env_var("XDG_DATA_HOME", report_errors));
if (category == ManifestCategory::explicit_layer) {
parse_and_add_env_var_override(paths, get_env_var("VK_LAYER_PATH", false)); // don't report failure
}
#include "shim.h"
+#include <algorithm>
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
static PlatformShim platform_shim;
extern "C" {
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
}
#endif
+#if defined(__APPLE__)
+FRAMEWORK_EXPORT CFBundleRef my_CFBundleGetMainBundle() {
+ static CFBundleRef global_bundle{};
+ return reinterpret_cast<CFBundleRef>(&global_bundle);
+}
+FRAMEWORK_EXPORT CFURLRef my_CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {
+ static CFURLRef global_url{};
+ return reinterpret_cast<CFURLRef>(&global_url);
+}
+FRAMEWORK_EXPORT Boolean my_CFURLGetFileSystemRepresentation(CFURLRef url, Boolean resolveAgainstBase, UInt8* buffer,
+ CFIndex maxBufLen) {
+ if (!platform_shim.bundle_contents.empty()) {
+ size_t copy_len = platform_shim.bundle_contents.size();
+ if (copy_len > maxBufLen) {
+ copy_len = maxBufLen;
+ }
+ strncpy(reinterpret_cast<char*>(buffer), platform_shim.bundle_contents.c_str(), copy_len);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
/* Shiming functions on apple is limited by the linker prefering to not use functions in the
* executable in loaded dylibs. By adding an interposer, we redirect the linker to use our
* version of the function over the real one, thus shimming the system function.
__attribute__((used)) static Interposer _interpose__secure_getenv MACOS_ATTRIB = {VOIDP_CAST(my__secure_getenv),
VOIDP_CAST(__secure_getenv)};
#endif
+__attribute__((used)) static Interposer _interpose_CFBundleGetMainBundle MACOS_ATTRIB = {VOIDP_CAST(my_CFBundleGetMainBundle),
+ VOIDP_CAST(CFBundleGetMainBundle)};
+__attribute__((used)) static Interposer _interpose_CFBundleCopyResourcesDirectoryURL MACOS_ATTRIB = {
+ VOIDP_CAST(my_CFBundleCopyResourcesDirectoryURL), VOIDP_CAST(CFBundleCopyResourcesDirectoryURL)};
+__attribute__((used)) static Interposer _interpose_CFURLGetFileSystemRepresentation MACOS_ATTRIB = {
+ VOIDP_CAST(my_CFURLGetFileSystemRepresentation), VOIDP_CAST(CFURLGetFileSystemRepresentation)};
+
#endif
} // extern "C"
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("implicit_layer_manifests"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("override_layer_manifests"));
folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("app_package_manifests"));
+ folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("macos_bundle"));
platform_shim->redirect_all_paths(get_folder(ManifestLocation::null).location());
if (set_default_search_paths) {
platform_shim->set_path(ManifestCategory::explicit_layer, get_folder(ManifestLocation::explicit_layer).location());
platform_shim->set_path(ManifestCategory::implicit_layer, get_folder(ManifestLocation::implicit_layer).location());
}
+#if defined(__APPLE__)
+ // Necessary since bundles look in sub folders for manifests, not the test framework folder itself
+ auto bundle_location = get_folder(ManifestLocation::macos_bundle).location();
+ platform_shim->redirect_path(bundle_location / "vulkan/icd.d", bundle_location);
+ platform_shim->redirect_path(bundle_location / "vulkan/explicit_layer.d", bundle_location);
+ platform_shim->redirect_path(bundle_location / "vulkan/implicit_layer.d", bundle_location);
+#endif
}
void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept {
if (icd_details.discovery_type == ManifestDiscoveryType::windows_app_package) {
folder = &get_folder(ManifestLocation::windows_app_package);
}
+ if (icd_details.discovery_type == ManifestDiscoveryType::macos_bundle) {
+ folder = &get_folder(ManifestLocation::macos_bundle);
+ }
if (!icd_details.is_fake) {
fs::path new_driver_name = fs::path(icd_details.icd_manifest.lib_path).stem() + "_" + std::to_string(cur_icd_index) +
fs::path(icd_details.icd_manifest.lib_path).extension();
add_env_var_vk_icd_filenames += (folder->location() / full_json_name).str();
set_env_var("VK_ADD_DRIVER_FILES", add_env_var_vk_icd_filenames);
break;
+ case (ManifestDiscoveryType::macos_bundle):
+ platform_shim->add_manifest(ManifestCategory::icd, icds.back().manifest_path);
case (ManifestDiscoveryType::none):
break;
#ifdef _WIN32
if (!env_var_vk_layer_paths.empty()) {
env_var_vk_layer_paths += OS_ENV_VAR_LIST_SEPARATOR;
}
- if(layer_details.is_dir) {
+ if (layer_details.is_dir) {
env_var_vk_layer_paths += fs_ptr->location().str();
} else {
env_var_vk_layer_paths += fs_ptr->location().str() + OS_ENV_VAR_LIST_SEPARATOR + layer_details.json_name;
case (ManifestDiscoveryType::override_folder):
fs_ptr = &get_folder(ManifestLocation::override_layer);
break;
+ case (ManifestDiscoveryType::macos_bundle):
+ fs_ptr = &(get_folder(ManifestLocation::macos_bundle));
+ break;
case (ManifestDiscoveryType::none):
break;
}
// index it directly using the enum location since they will always be in that order
return folders.at(static_cast<size_t>(location));
}
+#if defined(__APPLE__)
+void FrameworkEnvironment::setup_macos_bundle() noexcept {
+ platform_shim->bundle_contents = get_folder(ManifestLocation::macos_bundle).location().str();
+}
+#endif
const char* get_platform_wsi_extension(const char* api_selection) {
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
return "VK_KHR_android_surface";
add_env_var, // use the corresponding add-env-var for it
override_folder, // add to a special folder for the override layer to use
windows_app_package, // let the app package search find it
+ macos_bundle, // place it in a location only accessible to macos bundles
};
struct TestICDDetails {
implicit_layer = 6,
override_layer = 7,
windows_app_package = 8,
+ macos_bundle = 9,
};
struct FrameworkEnvironment {
fs::path get_layer_manifest_path(size_t index = 0) noexcept;
fs::FolderManager& get_folder(ManifestLocation location) noexcept;
-
+#if defined(__APPLE__)
+ // Set the path of the app bundle to the appropriate test framework bundle
+ void setup_macos_bundle() noexcept;
+#endif
PlatformShimWrapper platform_shim;
std::vector<fs::FolderManager> folders;
path operator/(std::string const& in) const;
path operator/(const char* in) const;
- // accesors
+ // accessors
path parent_path() const;
bool has_parent_path() const;
path filename() const;
// NOTE: This is a fake struct to make sure the pNext chain is properly passed down to the ICD
// vkEnumeratePhysicalDeviceGroups.
// The two versions must match:
- // "FakePNext" test in loader_regresion_tests.cpp
+ // "FakePNext" test in loader_regression_tests.cpp
// "test_vkEnumeratePhysicalDeviceGroups" in test_icd.cpp
struct FakePnextSharedWithICD {
VkStructureType sType;
inst.CheckCreate(VK_ERROR_INCOMPATIBLE_DRIVER);
}
#endif
+
+#if defined(__APPLE__)
+// Add two drivers, one to the bundle and one to the system locations
+TEST(ManifestDiscovery, AppleBundles) {
+ FrameworkEnvironment env{};
+ env.setup_macos_bundle();
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_discovery_type(ManifestDiscoveryType::macos_bundle));
+ env.get_test_icd(0).physical_devices.push_back({});
+ env.get_test_icd(0).physical_devices.at(0).properties.deviceID = 1337;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA));
+ env.get_test_icd(1).physical_devices.push_back({});
+ env.get_test_icd(1).physical_devices.at(0).properties.deviceID = 9999;
+
+ InstWrapper inst{env.vulkan_functions};
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+ auto physical_devices = inst.GetPhysDevs();
+ ASSERT_EQ(1, physical_devices.size());
+
+ // Verify that this is the 'right' GPU, aka the one from the bundle
+ VkPhysicalDeviceProperties props{};
+ inst->vkGetPhysicalDeviceProperties(physical_devices[0], &props);
+ ASSERT_EQ(env.get_test_icd(0).physical_devices.at(0).properties.deviceID, props.deviceID);
+}
+
+// Add two drivers, one to the bundle and one using the driver env-var
+TEST(ManifestDiscovery, AppleBundlesEnvVarActive) {
+ FrameworkEnvironment env{};
+ env.setup_macos_bundle();
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_discovery_type(ManifestDiscoveryType::macos_bundle));
+ env.get_test_icd(0).physical_devices.push_back({});
+ env.get_test_icd(0).physical_devices.at(0).properties.deviceID = 1337;
+ env.add_icd(TestICDDetails(TEST_ICD_PATH_VERSION_2_EXPORT_ICD_GPDPA).set_discovery_type(ManifestDiscoveryType::env_var));
+ env.get_test_icd(1).physical_devices.push_back({});
+ env.get_test_icd(1).physical_devices.at(0).properties.deviceID = 9999;
+
+ InstWrapper inst{env.vulkan_functions};
+ ASSERT_NO_FATAL_FAILURE(inst.CheckCreate());
+ auto physical_devices = inst.GetPhysDevs();
+ ASSERT_EQ(1, physical_devices.size());
+
+ // Verify that this is the 'right' GPU, aka the one from the env-var
+ VkPhysicalDeviceProperties props{};
+ inst->vkGetPhysicalDeviceProperties(physical_devices[0], &props);
+ ASSERT_EQ(env.get_test_icd(1).physical_devices.at(0).properties.deviceID, props.deviceID);
+}
+#endif