Skip to content

Commit

Permalink
loader: Match ICDs against DXGI adapters
Browse files Browse the repository at this point in the history
Previously, ICDs located through the HKLM registry would be loaded all
the time. This changes the loader to iterate DXGI adapters and only
loader the driver is there is an adapter that it corresponds to.

Change-Id: I204f37916b9e8ca668921507e68ef6e8e18a440a
  • Loading branch information
lenny-lunarg committed Sep 9, 2019
1 parent 42d4962 commit 19a5cdd
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 2 deletions.
4 changes: 2 additions & 2 deletions loader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ if(WIN32)
endif()

if(ENABLE_WIN10_ONECORE)
target_link_libraries(vulkan OneCoreUAP.lib LIBCMT.LIB LIBCMTD.LIB LIBVCRUNTIME.LIB LIBUCRT.LIB)
target_link_libraries(vulkan OneCoreUAP.lib LIBCMT.LIB LIBCMTD.LIB LIBVCRUNTIME.LIB LIBUCRT.LIB Dxgi)
set_target_properties(vulkan PROPERTIES LINK_FLAGS "/NODEFAULTLIB")
else()
target_link_libraries(vulkan Cfgmgr32)
target_link_libraries(vulkan Cfgmgr32 Dxgi)
endif()

add_dependencies(vulkan loader_asm_gen_files)
Expand Down
102 changes: 102 additions & 0 deletions loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
#include <devpkey.h>
#include <winternl.h>
#include <d3dkmthk.h>
#include <Dxgi1_6.h>

typedef _Check_return_ NTSTATUS (APIENTRY *PFN_D3DKMTEnumAdapters2)(const D3DKMT_ENUMADAPTERS2*);
typedef _Check_return_ NTSTATUS (APIENTRY *PFN_D3DKMTQueryAdapterInfo)(const D3DKMT_QUERYADAPTERINFO*);
Expand Down Expand Up @@ -779,6 +780,41 @@ static char *loader_get_next_path(char *path);
// When done using the returned string list, the caller should free the pointer.
VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *location, bool use_secondary_hive, char **reg_data,
PDWORD reg_data_size) {
// This list contains all of the allowed ICDs. This allows us to verify that a device is actually present from the vendor
// specified. This does disallow other vendors, but any new driver should use the device-specific registries anyway.
static const struct {
const char *filename;
int vendor_id;
} known_drivers[] = {
#if defined(_WIN64)
{
.filename = "igvk64.json",
.vendor_id = 0x8086,
},
{
.filename = "nv-vk64.json",
.vendor_id = 0x10de,
},
{
.filename = "amdvlk64.json",
.vendor_id = 0x1002,
},
#else
{
.filename = "igvk32.json",
.vendor_id = 0x8086,
},
{
.filename = "nv-vk32.json",
.vendor_id = 0x10de,
},
{
.filename = "amdvlk32.json",
.vendor_id = 0x1002,
},
#endif
};

LONG rtn_value;
HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key;
DWORD access_flags;
Expand All @@ -791,12 +827,25 @@ VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *locati
DWORD value_size = sizeof(value);
VkResult result = VK_SUCCESS;
bool found = false;
IDXGIFactory1 *dxgi_factory = NULL;
bool is_driver = !strcmp(location, VK_DRIVERS_INFO_REGISTRY_LOC);

if (NULL == reg_data) {
result = VK_ERROR_INITIALIZATION_FAILED;
goto out;
}

if (is_driver) {
HRESULT hres = CreateDXGIFactory1(&IID_IDXGIFactory1, &dxgi_factory);
if (hres != S_OK) {
loader_log(
inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
"loaderGetRegistryFiles: Failed to create dxgi factory for ICD registry verification. No ICDs will be added from "
"legacy registry locations");
goto out;
}
}

while (*loc) {
next = loader_get_next_path(loc);
access_flags = KEY_QUERY_VALUE;
Expand Down Expand Up @@ -831,9 +880,59 @@ VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *locati
*reg_data = new_ptr;
*reg_data_size *= 2;
}

// We've now found a json file. If this is an ICD, we still need to check if there is actually a device
// that matches this ICD
loader_log(
inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location);
if (is_driver) {
int i;
for (i = 0; i < sizeof(known_drivers) / sizeof(known_drivers[0]); ++i) {
if (!strcmp(name + strlen(name) - strlen(known_drivers[i].filename), known_drivers[i].filename)) {
break;
}
}
if (i == sizeof(known_drivers) / sizeof(known_drivers[0])) {
loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
"Dropping driver %s as it was not recognized as a known driver", name);
continue;
}

bool found_gpu = false;
for (int j = 0;; ++j) {
IDXGIAdapter1 *adapter;
HRESULT hres = dxgi_factory->lpVtbl->EnumAdapters1(dxgi_factory, j, &adapter);
if (hres == DXGI_ERROR_NOT_FOUND) {
break;
} else if (hres != S_OK) {
loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
"Failed to enumerate DXGI adapters at index %d. As a result, drivers may be skipped", j);
continue;
}

DXGI_ADAPTER_DESC1 description;
hres = adapter->lpVtbl->GetDesc1(adapter, &description);
if (hres != S_OK) {
loader_log(
inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
"Failed to get DXGI adapter information at index %d. As a result, drivers may be skipped", j);
continue;
}

if (description.VendorId == known_drivers[i].vendor_id) {
found_gpu = true;
break;
}
}

if (!found_gpu) {
loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
"Dropping driver %s as no corresponduing DXGI adapter was found", name);
continue;
}
}

if (strlen(*reg_data) == 0) {
// The list is emtpy. Add the first entry.
(void)snprintf(*reg_data, name_size + 1, "%s", name);
Expand Down Expand Up @@ -886,6 +985,9 @@ VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *locati
}

out:
if (is_driver && dxgi_factory != NULL) {
dxgi_factory->lpVtbl->Release(dxgi_factory);
}

return result;
}
Expand Down

0 comments on commit 19a5cdd

Please sign in to comment.