diff options
author | Jesse Natalie <jenatali@microsoft.com> | 2022-06-30 22:55:55 +0300 |
---|---|---|
committer | Charles Giessen <46324611+charles-lunarg@users.noreply.github.com> | 2022-07-05 23:34:53 +0300 |
commit | 26921924d63bda937feb0d7caf9258dfb2d1d894 (patch) | |
tree | df9d89fe32e4cc177a689b06e0f3009d2bdf346d | |
parent | 0ad591fa3c2a68e555e80f45a4d6cb52dfdaf8f0 (diff) |
Enable the Vulkan loader to load VulkanOn12/Dozen out of the D3DMappingLayers app package
-rw-r--r-- | docs/LoaderDriverInterface.md | 6 | ||||
-rw-r--r-- | loader/loader.c | 25 | ||||
-rw-r--r-- | loader/loader_windows.c | 70 | ||||
-rw-r--r-- | loader/loader_windows.h | 4 | ||||
-rw-r--r-- | tests/framework/shim/shim.h | 4 | ||||
-rw-r--r-- | tests/framework/shim/shim_common.cpp | 5 | ||||
-rw-r--r-- | tests/framework/shim/windows_shim.cpp | 49 | ||||
-rw-r--r-- | tests/framework/test_environment.cpp | 9 | ||||
-rw-r--r-- | tests/framework/test_environment.h | 14 | ||||
-rw-r--r-- | tests/loader_regression_tests.cpp | 11 |
10 files changed, 187 insertions, 10 deletions
diff --git a/docs/LoaderDriverInterface.md b/docs/LoaderDriverInterface.md index 1021dd41d..40430fbd8 100644 --- a/docs/LoaderDriverInterface.md +++ b/docs/LoaderDriverInterface.md @@ -291,6 +291,12 @@ In this case, the loader will open the first and last listings, but not the middle. This is because the value of 1 for vendor_b_vk.json disables the driver. +Additionally, the Vulkan loader will scan the system for well-known Windows +AppX/MSIX packages. If a package is found, the loader will scan the root directory +of this installed package for JSON manifest files. At this time, the only package +that is known is Microsoft's +[OpenCL™ and OpenGL® Compatibility Pack](https://apps.microsoft.com/store/detail/9NQPSL29BFFF?hl=en-us&gl=US). + The Vulkan loader will open each enabled manifest file found to obtain the name or pathname of a driver's shared library (".DLL") file. diff --git a/loader/loader.c b/loader/loader.c index 48a4d5b6f..b1eca3880 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -2917,7 +2917,9 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in bool xdg_data_dirs_secenv_alloc = true; #endif -#ifndef _WIN32 +#ifdef _WIN32 + char *package_path = NULL; +#else // Determine how much space is needed to generate the full search path // for the current manifest files. char *xdg_config_home = loader_secure_getenv("XDG_CONFIG_HOME", inst); @@ -3004,6 +3006,9 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in } additional_env = loader_secure_getenv(VK_ADDITIONAL_DRIVER_FILES_ENV_VAR, inst); relative_location = VK_DRIVERS_INFO_RELATIVE_DIR; +#ifdef _WIN32 + package_path = windows_get_app_package_manifest_path(inst); +#endif break; case LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER: relative_location = VK_ILAYERS_INFO_RELATIVE_DIR; @@ -3036,7 +3041,11 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in if (NULL != additional_env) { search_path_size += determine_data_file_path_size(additional_env, 0) + 2; #ifdef _WIN32 - } else { + } + if (NULL != package_path) { + search_path_size += determine_data_file_path_size(package_path, 0) + 2; + } + if (search_path_size == 2) { goto out; } #else // !_WIN32 @@ -3088,7 +3097,11 @@ static VkResult read_data_files_in_search_paths(const struct loader_instance *in copy_data_file_info(additional_env, NULL, 0, &cur_path_ptr); } -#ifndef _WIN32 +#ifdef _WIN32 + if (NULL != package_path) { + copy_data_file_info(package_path, NULL, 0, &cur_path_ptr); + } +#else if (rel_size > 0) { #if defined(__APPLE__) // Add the bundle's Resources dir to the beginning of the search path. @@ -3223,7 +3236,11 @@ out: if (NULL != override_env) { loader_free_getenv(override_env, inst); } -#ifndef _WIN32 +#ifdef _WIN32 + if (NULL != package_path) { + loader_instance_heap_free(inst, package_path); + } +#else if (xdg_config_home_secenv_alloc) { loader_free_getenv(xdg_config_home, inst); } diff --git a/loader/loader_windows.c b/loader/loader_windows.c index c7fbab9c8..1ad74e96c 100644 --- a/loader/loader_windows.c +++ b/loader/loader_windows.c @@ -51,6 +51,8 @@ #include <dxgi1_6.h> #include "adapters.h" +#include <appmodel.h> + #if !defined(NDEBUG) #include <crtdbg.h> #endif @@ -996,4 +998,72 @@ VkResult windows_sort_physical_device_groups(struct loader_instance *inst, const return VK_SUCCESS; } +char *windows_get_app_package_manifest_path(const struct loader_instance *inst) +{ + UINT32 numPackages = 0, bufferLength = 0; + /* This literal string identifies the Microsoft-published OpenCL and OpenGL Compatibility Pack + * (so named at the time this is being added), which contains OpenGLOn12 and OpenCLOn12 mapping + * layers, and will contain VulkanOn12 (aka Dozen) going forward. + */ + PCWSTR familyName = L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe"; + if (ERROR_INSUFFICIENT_BUFFER != GetPackagesByPackageFamily(familyName, + &numPackages, NULL, + &bufferLength, NULL) || + numPackages == 0 || bufferLength == 0) { + loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, + "windows_get_app_package_manifest_path: Failed to find mapping layers packages by family name\n"); + return NULL; + } + + char *ret = NULL; + WCHAR *buffer = loader_instance_heap_alloc(inst, sizeof(WCHAR) * bufferLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + PWSTR *packages = loader_instance_heap_alloc(inst, sizeof(PWSTR) * numPackages, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!buffer || !packages) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "windows_get_app_package_manifest_path: Failed to allocate memory for package names\n"); + goto cleanup; + } + + if (ERROR_SUCCESS != GetPackagesByPackageFamily(familyName, + &numPackages, packages, + &bufferLength, buffer)) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "windows_get_app_package_manifest_path: Failed to mapping layers package full names\n"); + goto cleanup; + } + + UINT32 pathLength = 0; + WCHAR path[MAX_PATH]; + memset(path, 0, sizeof(path)); + if (ERROR_INSUFFICIENT_BUFFER != GetPackagePathByFullName(packages[0], &pathLength, NULL) || + pathLength > MAX_PATH || + ERROR_SUCCESS != GetPackagePathByFullName(packages[0], &pathLength, path)) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "windows_get_app_package_manifest_path: Failed to get mapping layers package path\n"); + goto cleanup; + } + + int narrowPathLength = WideCharToMultiByte(CP_ACP, 0, path, -1, NULL, 0, NULL, NULL); + if (narrowPathLength == 0) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "windows_get_app_package_manifest_path: Failed to convert path from wide to narrow\n"); + goto cleanup; + } + + ret = loader_instance_heap_alloc(inst, narrowPathLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!ret) { + loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, + "windows_get_app_package_manifest_path: Failed to allocate path\n"); + goto cleanup; + } + + narrowPathLength = WideCharToMultiByte(CP_ACP, 0, path, -1, ret, narrowPathLength, NULL, NULL); + assert((size_t)narrowPathLength == strlen(ret) + 1); + +cleanup: + loader_instance_heap_free(inst, buffer); + loader_instance_heap_free(inst, packages); + return ret; +} + #endif // _WIN32 diff --git a/loader/loader_windows.h b/loader/loader_windows.h index ff7555c0b..2e34f6574 100644 --- a/loader/loader_windows.h +++ b/loader/loader_windows.h @@ -111,4 +111,8 @@ VkResult windows_sort_physical_device_groups(struct loader_instance *inst, const // Creates a DXGI factory // Returns VkLoaderFeatureFlags containing VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING if successful, otherwise 0 VkLoaderFeatureFlags windows_initialize_dxgi(void); + +// Retrieve a path to an installed app package that contains Vulkan manifests. +// When done using the returned string, the caller should free the pointer. +char *windows_get_app_package_manifest_path(const struct loader_instance *inst); #endif // WIN32
\ No newline at end of file diff --git a/tests/framework/shim/shim.h b/tests/framework/shim/shim.h index bb0ad9a30..4b0c8bc23 100644 --- a/tests/framework/shim/shim.h +++ b/tests/framework/shim/shim.h @@ -37,6 +37,7 @@ #include <initguid.h> #include <devpkey.h> #include <winternl.h> +#include <appmodel.h> #define CINTERFACE #include <dxgi1_6.h> @@ -151,6 +152,7 @@ struct PlatformShim { void add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 desc1); void add_d3dkmt_adapter(D3DKMT_Adapter const& adapter); + void set_app_package_path(fs::path const& path); uint32_t next_adapter_handle = 1; // increment everytime add_dxgi_adapter is called std::vector<DXGIAdapter> dxgi_adapters; @@ -173,6 +175,8 @@ struct PlatformShim { std::vector<RegistryEntry> hkey_local_machine_implicit_layers; std::vector<RegistryEntry> hkey_local_machine_drivers; + std::wstring app_package_path; + // When a key is created, return the index of the size_t created_key_count = 0; std::vector<HKeyHandle> created_keys; diff --git a/tests/framework/shim/shim_common.cpp b/tests/framework/shim/shim_common.cpp index 721aabef5..e946c0d4c 100644 --- a/tests/framework/shim/shim_common.cpp +++ b/tests/framework/shim/shim_common.cpp @@ -118,6 +118,11 @@ void PlatformShim::add_dxgi_adapter(GpuType gpu_preference, DXGI_ADAPTER_DESC1 d void PlatformShim::add_d3dkmt_adapter(D3DKMT_Adapter const& adapter) { d3dkmt_adapters.push_back(adapter); } +void PlatformShim::set_app_package_path(fs::path const& path) { + app_package_path.resize(path.size()); + MultiByteToWideChar(CP_UTF8, 0, path.c_str(), -1, &app_package_path[0], static_cast<int>(app_package_path.size())); +} + // TODO: void PlatformShim::add_CM_Device_ID(std::wstring const& id, fs::path const& icd_path, fs::path const& layer_path) { // // append a null byte as separator if there is already id's in the list diff --git a/tests/framework/shim/windows_shim.cpp b/tests/framework/shim/windows_shim.cpp index 15117606e..c847234af 100644 --- a/tests/framework/shim/windows_shim.cpp +++ b/tests/framework/shim/windows_shim.cpp @@ -379,6 +379,51 @@ LSTATUS __stdcall ShimRegCloseKey(HKEY hKey) { return ERROR_SUCCESS; } +// Windows app package shims +using PFN_GetPackagesByPackageFamily = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *); +static PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = GetPackagesByPackageFamily; +using PFN_GetPackagePathByFullName = LONG(WINAPI *)(PCWSTR, UINT32 *, PWSTR); +static PFN_GetPackagePathByFullName fpGetPackagePathByFullName = GetPackagePathByFullName; + +static constexpr wchar_t package_full_name[] = L"ThisIsARandomStringSinceTheNameDoesn'tMatter"; +LONG WINAPI ShimGetPackagesByPackageFamily(_In_ PCWSTR packageFamilyName, _Inout_ UINT32 *count, + _Out_writes_opt_(*count) PWSTR *packageFullNames, _Inout_ UINT32 *bufferLength, + _Out_writes_opt_(*bufferLength) WCHAR *buffer) { + if (!packageFamilyName || !count || !bufferLength) return ERROR_INVALID_PARAMETER; + if (!platform_shim.app_package_path.empty() && wcscmp(packageFamilyName, L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe") == 0) { + if (*count > 0 && !packageFullNames) return ERROR_INVALID_PARAMETER; + if (*bufferLength > 0 && !buffer) return ERROR_INVALID_PARAMETER; + if (*count > 1) return ERROR_INVALID_PARAMETER; + bool too_small = *count < 1 || *bufferLength < ARRAYSIZE(package_full_name); + *count = 1; + *bufferLength = ARRAYSIZE(package_full_name); + if (too_small) return ERROR_INSUFFICIENT_BUFFER; + + wcscpy(buffer, package_full_name); + *packageFullNames = buffer; + return 0; + } + *count = 0; + *bufferLength = 0; + return 0; +} + +LONG WINAPI ShimGetPackagePathByFullName(_In_ PCWSTR packageFullName, _Inout_ UINT32 *pathLength, + _Out_writes_opt_(*pathLength) PWSTR path) { + if (!packageFullName || !pathLength) return ERROR_INVALID_PARAMETER; + if (*pathLength > 0 && !path) return ERROR_INVALID_PARAMETER; + if (wcscmp(packageFullName, package_full_name) != 0) { + *pathLength = 0; + return 0; + } + if (*pathLength < platform_shim.app_package_path.size() + 1) { + *pathLength = static_cast<UINT32>(platform_shim.app_package_path.size() + 1); + return ERROR_INSUFFICIENT_BUFFER; + } + wcscpy(path, platform_shim.app_package_path.c_str()); + return 0; +} + // Initialization void WINAPI DetourFunctions() { if (!gdi32_dll) { @@ -426,6 +471,8 @@ void WINAPI DetourFunctions() { DetourAttach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA); DetourAttach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA); DetourAttach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey); + DetourAttach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily); + DetourAttach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName); LONG error = DetourTransactionCommit(); if (error != NO_ERROR) { @@ -453,6 +500,8 @@ void DetachFunctions() { DetourDetach(&(PVOID &)fpRegQueryValueExA, (PVOID)ShimRegQueryValueExA); DetourDetach(&(PVOID &)fpRegEnumValueA, (PVOID)ShimRegEnumValueA); DetourDetach(&(PVOID &)fpRegCloseKey, (PVOID)ShimRegCloseKey); + DetourDetach(&(PVOID &)fpGetPackagesByPackageFamily, (PVOID)ShimGetPackagesByPackageFamily); + DetourDetach(&(PVOID &)fpGetPackagePathByFullName, (PVOID)ShimGetPackagePathByFullName); DetourTransactionCommit(); } diff --git a/tests/framework/test_environment.cpp b/tests/framework/test_environment.cpp index 92c88bb8f..7654be723 100644 --- a/tests/framework/test_environment.cpp +++ b/tests/framework/test_environment.cpp @@ -194,6 +194,7 @@ FrameworkEnvironment::FrameworkEnvironment() noexcept : platform_shim(&folders), folders.emplace_back(FRAMEWORK_BUILD_DIRECTORY, std::string("explicit_add_env_var_layer_folder")); 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")); platform_shim->redirect_all_paths(get_folder(ManifestLocation::null).location()); platform_shim->set_path(ManifestCategory::icd, get_folder(ManifestLocation::driver).location()); @@ -208,6 +209,9 @@ void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept { icd_details.discovery_type == ManifestDiscoveryType::add_env_var) { folder = &get_folder(ManifestLocation::driver_env_var); } + if (icd_details.discovery_type == ManifestDiscoveryType::windows_app_package) { + folder = &get_folder(ManifestLocation::windows_app_package); + } 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(); @@ -242,6 +246,11 @@ void FrameworkEnvironment::add_icd(TestICDDetails icd_details) noexcept { break; case (ManifestDiscoveryType::none): break; +#ifdef _WIN32 + case (ManifestDiscoveryType::windows_app_package): + platform_shim->set_app_package_path(folder->location()); + break; +#endif } } diff --git a/tests/framework/test_environment.h b/tests/framework/test_environment.h index 4d33c28df..a9259138d 100644 --- a/tests/framework/test_environment.h +++ b/tests/framework/test_environment.h @@ -303,11 +303,12 @@ struct TestLayerHandle { }; enum class ManifestDiscoveryType { - generic, // put the manifest in the regular locations - none, // don't add to regular locations - eg D3DKMT - env_var, // use the corresponding env-var for it - add_env_var, // use the corresponding add-env-var for it - override_folder, // add to a special folder for the override layer to use + generic, // put the manifest in the regular locations + none, // don't add to regular locations - eg D3DKMT + env_var, // use the corresponding env-var for it + 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 }; struct TestICDDetails { @@ -338,7 +339,8 @@ enum class ManifestLocation { explicit_layer_env_var = 4, explicit_layer_add_env_var = 5, implicit_layer = 6, - override_layer = 7 + override_layer = 7, + windows_app_package = 8, }; struct FrameworkEnvironment { diff --git a/tests/loader_regression_tests.cpp b/tests/loader_regression_tests.cpp index bd8fdeebf..ea71f10e5 100644 --- a/tests/loader_regression_tests.cpp +++ b/tests/loader_regression_tests.cpp @@ -3355,3 +3355,14 @@ TEST(PortabilityICDConfiguration, PortabilityAndRegularICDPreInstanceFunctions) ASSERT_EQ(layer_count, 0U); } } + +#ifdef _WIN32 +TEST(AppPackageDriverDiscovery, AppPackageTest) { + FrameworkEnvironment env; + env.add_icd(TestICDDetails{TEST_ICD_PATH_VERSION_2}.set_discovery_type(ManifestDiscoveryType::windows_app_package)); + env.get_test_icd().physical_devices.push_back({}); + + InstWrapper inst{env.vulkan_functions}; + inst.CheckCreate(); +} +#endif |