aboutsummaryrefslogtreecommitdiff
path: root/loader/loader.c
diff options
context:
space:
mode:
authorSlawomir Cygan <slawomir.cygan@intel.com>2017-07-03 16:47:52 +0200
committerLenny Komow <lenny@lunarg.com>2017-08-10 09:49:24 -0600
commit3b71bfe5d70d682f531725491eaf9f9f417daf99 (patch)
treec3f07658cc8bf0dde6996576c8f4b66dc2b05ccc /loader/loader.c
parent6060d82ee6ab93770ad96baca8923d6a836bcc51 (diff)
downloadusermoji-3b71bfe5d70d682f531725491eaf9f9f417daf99.tar.xz
loader: Add new ICD search paths to loader
This change extends the functionality of searching for ICD JSONs by adding registry locations specific to given display adapter and software components associated with this display adapter. The exact locations in registry are queried using Windows public PnP Configuration Manager API[1]. This change is required, as previous ICD locations (constant path in "HKLM/Software") may be unreachable for drivers and their installers on Windows RS3[2]. Similar change is being made for OpenCL[2] [1]https://msdn.microsoft.com/en-us/library/windows/hardware/ff549713.aspx [2]https://github.com/KhronosGroup/OpenCL-ICD-Loader/pull/21
Diffstat (limited to 'loader/loader.c')
-rw-r--r--loader/loader.c261
1 files changed, 258 insertions, 3 deletions
diff --git a/loader/loader.c b/loader/loader.c
index 468804f5..c75bcf79 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -47,6 +47,12 @@
#include "cJSON.h"
#include "murmurhash.h"
+#if defined(_WIN32)
+#include <Cfgmgr32.h>
+#include <initguid.h>
+#include <Devpkey.h>
+#endif
+
// This is a CMake generated file with #defines for any functions/includes
// that it found present. This is currently necessary to properly determine
// if secure_getenv or __secure_getenv are present
@@ -401,6 +407,245 @@ VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object
}
#if defined(WIN32)
+// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr.
+//
+// This function looks for filename in given device handle, filename is then added to return list
+// function return true if filename was appended to reg_data list
+// If error occures result is updated with failure reason
+bool loaderGetDeviceRegistryEntry(const struct loader_instance *inst, char **reg_data,PDWORD total_size, DEVINST devID, VkResult *result)
+{
+ HKEY hkrKey = INVALID_HANDLE_VALUE;
+ DWORD requiredSize, dataType;
+ char *pVkDriverPath = NULL;
+ bool found = false;
+
+ if (NULL == total_size || NULL == reg_data) {
+ *result = VK_ERROR_INITIALIZATION_FAILED;
+ return false;
+ }
+
+ CONFIGRET status = CM_Open_DevNode_Key(devID, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkrKey, CM_REGISTRY_SOFTWARE);
+ if (status != CR_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: Failed to open registry key for DeviceID(%d)", devID);
+ *result = VK_ERROR_INITIALIZATION_FAILED;
+ return false;
+ }
+
+ // query value
+ LSTATUS ret = RegQueryValueEx(
+ hkrKey,
+ HKR_VK_DRIVER_NAME,
+ NULL,
+ NULL,
+ NULL,
+ &requiredSize);
+
+ if (ret != ERROR_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain VulkanDriverName size", devID);
+ goto out;
+ }
+
+ pVkDriverPath = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (pVkDriverPath == NULL) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: Failed to allocate space for DriverName.");
+ *result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+
+ ret = RegQueryValueEx(
+ hkrKey,
+ HKR_VK_DRIVER_NAME,
+ NULL,
+ &dataType,
+ pVkDriverPath,
+ &requiredSize
+ );
+
+ if (ret != ERROR_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain VulkanDriverName");
+
+ *result = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ if (dataType != REG_SZ) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: Invalid VulkanDriverName data type. Expected REG_SZ.");
+ *result = VK_ERROR_INITIALIZATION_FAILED;
+ goto out;
+ }
+
+ if (NULL == *reg_data) {
+ *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == *reg_data) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: Failed to allocate space for registry data for key %s", pVkDriverPath);
+ *result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ *reg_data[0] = '\0';
+ } else if (strlen(*reg_data) + requiredSize + 1 > *total_size) {
+ void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2,
+ VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (NULL == new_ptr) {
+ loader_log(
+ inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryEntry: Failed to reallocate space for registry value of size %d for key %s",
+ *total_size * 2, pVkDriverPath);
+ *result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ goto out;
+ }
+ *reg_data = new_ptr;
+ *total_size *= 2;
+ }
+
+ if (strlen(*reg_data) == 0) {
+ (void)snprintf(*reg_data, requiredSize + 1, "%s", pVkDriverPath);
+ } else {
+ (void)snprintf(*reg_data + strlen(*reg_data), requiredSize + 2, "%c%s", PATH_SEPARATOR, pVkDriverPath);
+ }
+ found = true;
+
+out:
+ if (pVkDriverPath != NULL) {
+ loader_instance_heap_free(inst, pVkDriverPath);
+ }
+ RegCloseKey(hkrKey);
+ return found;
+}
+
+// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr .
+//
+// This function looks for display devices and childish software components
+// for a list of files which are added to a returned list (function return
+// value).
+// Function return is a string with a ';' separated list of filenames.
+// Function return is NULL if no valid name/value pairs are found in the key,
+// or the key is not found.
+//
+// *reg_data contains a string list of filenames as pointer.
+// When done using the returned string list, the caller should free the pointer.
+VkResult loaderGetDeviceRegistryFiles(const struct loader_instance *inst, char **reg_data) {
+ static const char* softwareComponentGUID = "{5c4c3332-344d-483c-8739-259e934c9cc8}";
+ static const char* displayGUID = "{4d36e968-e325-11ce-bfc1-08002be10318}";
+ const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
+
+ char childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {}
+ ULONG childGuidSize = sizeof(childGuid);
+
+ DEVINST devID = 0, childID = 0;
+ DWORD totalSize = 4096;
+ char *pDeviceNames = NULL;
+ ULONG deviceNamesSize = 0;
+ VkResult result = VK_SUCCESS;
+ bool found = false;
+
+ if (NULL == reg_data) {
+ result = VK_ERROR_INITIALIZATION_FAILED;
+ return result;
+ }
+
+ // if after obtaining the DeviceNameSize, new device is added start over
+ do {
+ CM_Get_Device_ID_List_Size(&deviceNamesSize, displayGUID, flags);
+
+ if (pDeviceNames != NULL) {
+ loader_instance_heap_free(inst, pDeviceNames);
+ }
+
+ pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (pDeviceNames == NULL) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetDeviceRegistryFiles: Failed to allocate space for display device names.");
+ result = VK_ERROR_OUT_OF_HOST_MEMORY;
+ return false;
+ }
+ } while (CM_Get_Device_ID_List(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL);
+
+ if (pDeviceNames) {
+
+ for (char *deviceName = pDeviceNames; *deviceName; deviceName += strlen(deviceName) + 1) {
+ CONFIGRET status = CM_Locate_DevNode(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
+ if (CR_SUCCESS != status) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetRegistryFiles: failed to open DevNode %s", deviceName);
+ continue;
+ }
+ ULONG ulStatus, ulProblem;
+ status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
+
+ if (CR_SUCCESS != status)
+ {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetRegistryFiles: failed to probe device status %s", deviceName);
+ continue;
+ }
+ if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART))
+ {
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetRegistryFiles: device %s is pending reboot, skipping ...", deviceName);
+ continue;
+ }
+
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetRegistryFiles: opening device %s", deviceName);
+
+ if (loaderGetDeviceRegistryEntry(inst, reg_data, &totalSize, devID, &result)) {
+ found = true;
+ continue;
+ }
+
+ status = CM_Get_Child(&childID, devID, 0);
+ if (status != CR_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetRegistryFiles: unable to open child-device error:%d", status);
+ continue;
+ }
+
+ do {
+ char buffer[MAX_DEVICE_ID_LEN];
+ CM_Get_Device_ID(childID, buffer, MAX_DEVICE_ID_LEN, 0);
+
+ loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
+ "loaderGetRegistryFiles: Opening child device %d - %s", childID, buffer);
+
+ status = CM_Get_DevNode_Registry_Property(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
+ if (status != CR_SUCCESS) {
+ loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
+ "loaderGetRegistryFiles: unable to obtain GUID for:%d error:%d", childID, status);
+
+ result = VK_ERROR_INITIALIZATION_FAILED;
+ continue;
+ }
+
+ if (strcmp(childGuid, softwareComponentGUID) != 0) {
+ loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
+ "loaderGetRegistryFiles: GUID for %d is not SoftwareComponent skipping", childID);
+ continue;
+ }
+
+ if (loaderGetDeviceRegistryEntry(inst, reg_data, &totalSize, childID, &result)) {
+ found = true;
+ break; // check next-display-device
+ }
+
+ } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS);
+ }
+
+ loader_instance_heap_free(inst, pDeviceNames);
+ }
+
+ if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
+ result = VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ return result;
+}
+
static char *loader_get_next_path(char *path);
// Find the list of registry files (names within a key) in key "location".
@@ -491,7 +736,7 @@ VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *locati
}
}
- if (!found) {
+ if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
result = VK_ERROR_INITIALIZATION_FAILED;
}
@@ -2746,14 +2991,24 @@ static VkResult loader_get_manifest_files(const struct loader_instance *inst, co
*loc_write = '\0';
#if defined(_WIN32)
+ VkResult regHKR_result = VK_SUCCESS;
+
+ if (!strncmp(loc, DEFAULT_VK_DRIVERS_INFO, sizeof(DEFAULT_VK_DRIVERS_INFO)))
+ {
+ regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg);
+ }
+
VkResult reg_result = loaderGetRegistryFiles(inst, loc, is_layer, &reg);
- if (VK_SUCCESS != reg_result || NULL == reg) {
+
+ if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == reg) {
if (!is_layer) {
loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
"loader_get_manifest_files: Registry lookup failed "
"to get ICD manifest files. Possibly missing Vulkan"
" driver?");
- if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
+ if (VK_SUCCESS == regHKR_result || VK_ERROR_OUT_OF_HOST_MEMORY == regHKR_result) {
+ res = regHKR_result;
+ } else if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
res = reg_result;
} else {
res = VK_ERROR_INCOMPATIBLE_DRIVER;