loader: Get ICDs by calling enum adapter function Change-Id: I5faa4e78ec1e445122ed7d640cc296c33d8a7aa4
diff --git a/loader/loader.c b/loader/loader.c index 0c480d7..841a02f 100644 --- a/loader/loader.c +++ b/loader/loader.c
@@ -25,6 +25,12 @@ * */ +// This needs to be defined first, or else we'll get redefinitions on NTSTATUS values +#ifdef _WIN32 +#define UMDF_USING_NTSTATUS +#include <ntstatus.h> +#endif + #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -63,6 +69,8 @@ #include <Cfgmgr32.h> #include <initguid.h> #include <Devpkey.h> +#include <winternl.h> +#include <d3dkmthk.h> #endif // This is a CMake generated file with #defines for any functions/includes @@ -3706,6 +3714,118 @@ } #ifdef _WIN32 +// Read manifest JSON files uing the Windows driver interface +static VkResult ReadManifestsFromD3DAdapters(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, const wchar_t* value_name) +{ + VkResult result = VK_INCOMPLETE; + D3DKMT_ENUMADAPTERS2 adapters = { + .NumAdapters = 0, + .pAdapters = NULL + }; + D3DDDI_QUERYREGISTRY_INFO *full_info = NULL; + char *json_path = NULL; + + // Get all of the adapters + NTSTATUS status = D3DKMTEnumAdapters2(&adapters); + if (status == STATUS_SUCCESS && adapters.NumAdapters > 0) { + adapters.pAdapters = loader_instance_heap_alloc(inst, sizeof(D3DKMT_ADAPTERINFO) * adapters.NumAdapters, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (adapters.pAdapters == NULL) { + goto out; + } + status = D3DKMTEnumAdapters2(&adapters); + } + if (status != STATUS_SUCCESS) { + goto out; + } + + // If that worked, we need to get the manifest file(s) for each adapter + for (ULONG i = 0; i < adapters.NumAdapters; ++i) { + + // The first query should just check if the field exists and how big it is + D3DDDI_QUERYREGISTRY_INFO filename_info = { + .QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY, + .ValueType = REG_MULTI_SZ, + .PhysicalAdapterIndex = 0, + }; + wcsncpy(filename_info.ValueName, value_name, sizeof(filename_info.ValueName) / sizeof(DWORD)); + D3DKMT_QUERYADAPTERINFO query_info = { + .hAdapter = adapters.pAdapters[i].hAdapter, + .Type = KMTQAITYPE_QUERYREGISTRY, + .pPrivateDriverData = &filename_info, + .PrivateDriverDataSize = sizeof(filename_info), + }; + status = D3DKMTQueryAdapterInfo(&query_info); + + // This error indicates that the type didn't match, so we'll try a REG_SZ + if (status == STATUS_INVALID_PARAMETER) { + filename_info.ValueType = REG_SZ; + status = D3DKMTQueryAdapterInfo(&query_info); + } + + if (status != STATUS_SUCCESS) { + continue; + } + + // The second query needs to allocate space for the string to overflow out the back of the struct + size_t full_size = sizeof(filename_info) + (filename_info.OutputValueSize * sizeof(WCHAR)); + full_info = loader_instance_heap_alloc(inst, full_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (full_info == NULL) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + memcpy(full_info, &filename_info, sizeof(filename_info)); + query_info.pPrivateDriverData = full_info; + query_info.PrivateDriverDataSize = (UINT) full_size; + status = D3DKMTQueryAdapterInfo(&query_info); + if (status != STATUS_SUCCESS) { + goto out; + } + + // Convert the wide string to a narrow string + json_path = loader_instance_heap_alloc(inst, full_info->OutputValueSize, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (json_path == NULL) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto out; + } + + // Iterate over each component string + for (const wchar_t *curr_path = full_info->OutputString; curr_path[0] != '\0'; curr_path += wcslen(curr_path) + 1) { + WideCharToMultiByte(CP_UTF8, 0, curr_path, full_info->OutputValueSize / sizeof(WCHAR), json_path, full_info->OutputValueSize, NULL, NULL); + + // Add the string to the output list + result = VK_SUCCESS; + loaderAddJsonEntry(inst, reg_data, reg_data_size, (LPCTSTR) L"EnumAdapters", REG_SZ, json_path, (DWORD) strlen(json_path) + 1, &result); + if (result != VK_SUCCESS) { + goto out; + } + + // If this is a string and not a multi-string, we don't want to go throught the loop more than once + if (full_info->ValueType == REG_SZ) { + break; + } + } + + loader_instance_heap_free(inst, json_path); + json_path = NULL; + loader_instance_heap_free(inst, full_info); + full_info = NULL; + } + +out: + if (json_path != NULL) { + loader_instance_heap_free(inst, json_path); + } + if (full_info != NULL) { + loader_instance_heap_free(inst, full_info); + } + if (adapters.pAdapters != NULL) { + loader_instance_heap_free(inst, adapters.pAdapters); + } + + return result; +} + // Look for data files in the registry. static VkResult ReadDataFilesInRegistry(const struct loader_instance *inst, enum loader_data_files_type data_file_type, bool warn_if_not_present, char *registry_location, struct loader_data_files *out_files) { @@ -3718,11 +3838,21 @@ VkResult regHKR_result = VK_SUCCESS; DWORD reg_size = 4096; if (!strncmp(registry_location, VK_DRIVERS_INFO_REGISTRY_LOC, sizeof(VK_DRIVERS_INFO_REGISTRY_LOC))) { - regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpDriverRegistry()); + // If we're looking for drivers we need to try enumerating adapters + regHKR_result = ReadManifestsFromD3DAdapters(inst, &search_path, ®_size, LoaderPnpDriverRegistryWide()); + if (regHKR_result == VK_INCOMPLETE) { + regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpDriverRegistry()); + } } else if (!strncmp(registry_location, VK_ELAYERS_INFO_REGISTRY_LOC, sizeof(VK_ELAYERS_INFO_REGISTRY_LOC))) { - regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpELayerRegistry()); + regHKR_result = ReadManifestsFromD3DAdapters(inst, &search_path, ®_size, LoaderPnpELayerRegistryWide()); + if (regHKR_result == VK_INCOMPLETE) { + regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpELayerRegistry()); + } } else if (!strncmp(registry_location, VK_ILAYERS_INFO_REGISTRY_LOC, sizeof(VK_ILAYERS_INFO_REGISTRY_LOC))) { - regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpILayerRegistry()); + regHKR_result = ReadManifestsFromD3DAdapters(inst, &search_path, ®_size, LoaderPnpILayerRegistryWide()); + if (regHKR_result == VK_INCOMPLETE) { + regHKR_result = loaderGetDeviceRegistryFiles(inst, &search_path, ®_size, LoaderPnpILayerRegistry()); + } } // This call looks into the Khronos non-device specific section of the registry.
diff --git a/loader/vk_loader_platform.h b/loader/vk_loader_platform.h index dd6b3fd..a91c648 100644 --- a/loader/vk_loader_platform.h +++ b/loader/vk_loader_platform.h
@@ -207,7 +207,12 @@ static inline const char *LoaderPnpDriverRegistry() { BOOL is_wow; IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? (API_NAME "DriverNameWow") : (API_NAME "DriverName"); + return is_wow ? "VulkanDriverNameWow" : "VulkanDriverName"; +} +static inline const wchar_t *LoaderPnpDriverRegistryWide() { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"VulkanDriverNameWow" : L"VulkanDriverName"; } // Get the key for the plug 'n play explicit layer registry @@ -215,15 +220,25 @@ static inline const char *LoaderPnpELayerRegistry() { BOOL is_wow; IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? (API_NAME "ExplicitLayersWow") : (API_NAME "ExplicitLayers"); + return is_wow ? "VulkanExplicitLayersWow" : "VulkanExplicitLayers"; } +static inline const wchar_t *LoaderPnpELayerRegistryWide() { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"VulkanExplicitLayersWow" : L"VulkanExplicitLayers"; +} + // Get the key for the plug 'n play implicit layer registry // The string returned by this function should NOT be freed - static inline const char *LoaderPnpILayerRegistry() { BOOL is_wow; IsWow64Process(GetCurrentProcess(), &is_wow); - return is_wow ? (API_NAME "ImplicitLayersWow") : (API_NAME "ImplicitLayers"); + return is_wow ? "VulkanImplicitLayersWow" : "VulkanImplicitLayers"; +} +static inline const wchar_t *LoaderPnpILayerRegistryWide() { + BOOL is_wow; + IsWow64Process(GetCurrentProcess(), &is_wow); + return is_wow ? L"VulkanImplicitLayersWow" : L"VulkanImplicitLayers"; } #endif