loader: Get ICDs by calling enum adapter function
Change-Id: I5faa4e78ec1e445122ed7d640cc296c33d8a7aa4
diff --git a/loader/loader.c b/loader/loader.c
index f2db792..260b193 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,11 @@
#include <Cfgmgr32.h>
#include <initguid.h>
#include <Devpkey.h>
+#include <winternl.h>
+#include <d3dkmthk.h>
+
+typedef _Check_return_ NTSTATUS (APIENTRY *PFN_D3DKMTEnumAdapters2)(const D3DKMT_ENUMADAPTERS2*);
+typedef _Check_return_ NTSTATUS (APIENTRY *PFN_D3DKMTQueryAdapterInfo)(const D3DKMT_QUERYADAPTERINFO*);
#endif
// This is a CMake generated file with #defines for any functions/includes
@@ -2287,6 +2298,12 @@
.malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
};
cJSON_InitHooks(&alloc_fns);
+
+#if defined(_WIN32)
+ // This is needed to ensure that newer APIs are available right away
+ // and not after the first call that has been statically linked
+ LoadLibrary("gdi32.dll");
+#endif
}
struct loader_data_files {
@@ -3793,6 +3810,138 @@
}
#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;
+ size_t full_info_size = 0;
+ char *json_path = NULL;
+ size_t json_path_size = 0;
+
+ PFN_D3DKMTEnumAdapters2 fpD3DKMTEnumAdapters2 =
+ (PFN_D3DKMTEnumAdapters2)GetProcAddress(GetModuleHandle("gdi32.dll"), "D3DKMTEnumAdapters2");
+ PFN_D3DKMTQueryAdapterInfo fpD3DKMTQueryAdapterInfo =
+ (PFN_D3DKMTQueryAdapterInfo)GetProcAddress(GetModuleHandle("gdi32.dll"), "D3DKMTQueryAdapterInfo");
+ if (fpD3DKMTEnumAdapters2 == NULL || fpD3DKMTQueryAdapterInfo == NULL) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+
+ // Get all of the adapters
+ NTSTATUS status = fpD3DKMTEnumAdapters2(&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 = fpD3DKMTEnumAdapters2(&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,
+ .QueryFlags =
+ {
+ .TranslatePath = true,
+ },
+ .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 = fpD3DKMTQueryAdapterInfo(&query_info);
+
+ // This error indicates that the type didn't match, so we'll try a REG_SZ
+ if (status != STATUS_SUCCESS) {
+ filename_info.ValueType = REG_SZ;
+ status = fpD3DKMTQueryAdapterInfo(&query_info);
+ }
+
+ if (status != STATUS_SUCCESS || filename_info.Status != D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW) {
+ continue;
+ }
+
+ while (status == STATUS_SUCCESS && ((D3DDDI_QUERYREGISTRY_INFO *)query_info.pPrivateDriverData)->Status ==
+ D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW) {
+ bool needs_copy = (full_info == NULL);
+ size_t full_size = sizeof(D3DDDI_QUERYREGISTRY_INFO) + filename_info.OutputValueSize;
+ void *buffer =
+ loader_instance_heap_realloc(inst, full_info, full_info_size, full_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (buffer == NULL) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ full_info = buffer;
+ full_info_size = full_size;
+
+ if (needs_copy) {
+ memcpy(full_info, &filename_info, sizeof(D3DDDI_QUERYREGISTRY_INFO));
+ }
+ query_info.pPrivateDriverData = full_info;
+ query_info.PrivateDriverDataSize = (UINT)full_info_size;
+ status = fpD3DKMTQueryAdapterInfo(&query_info);
+ }
+
+ if (status != STATUS_SUCCESS || full_info->Status != D3DDDI_QUERYREGISTRY_STATUS_SUCCESS) {
+ goto out;
+ }
+
+ // Convert the wide string to a narrow string
+ void *buffer = loader_instance_heap_realloc(inst, json_path, json_path_size, full_info->OutputValueSize,
+ VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+ if (buffer == NULL) {
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ json_path = buffer;
+ json_path_size = full_info->OutputValueSize;
+
+ // 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, -1, json_path, (int)json_path_size, 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;
+ }
+ }
+ }
+
+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) {
@@ -3805,11 +3954,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