diff --git a/opencl/api/opencl/khronos/icd/OpenCL.rc b/opencl/api/opencl/khronos/icd/OpenCL.rc index 9778fcb4de..16914f4f53 100644 --- a/opencl/api/opencl/khronos/icd/OpenCL.rc +++ b/opencl/api/opencl/khronos/icd/OpenCL.rc @@ -40,8 +40,8 @@ #ifdef RC_INVOKED VS_VERSION_INFO VERSIONINFO -FILEVERSION 2,2,0,0 -PRODUCTVERSION 2,2,0,0 +FILEVERSION 2,2,1,0 +PRODUCTVERSION 2,2,1,0 FILETYPE VFT_DLL BEGIN @@ -52,8 +52,7 @@ BEGIN VALUE "FileDescription" ,"OpenCL Client DLL" VALUE "ProductName" ,"Khronos OpenCL ICD" VALUE "LegalCopyright" ,"Copyright \251 The Khronos Group Inc 2016" - VALUE "FileVersion" ,"2.2.0.0" - + VALUE "FileVersion" ,"2.2.1.0" VALUE "CompanyName" ,"Khronos Group" VALUE "InternalName" ,"OpenCL" VALUE "OriginalFilename","OpenCL.dll" diff --git a/opencl/api/opencl/khronos/icd/icd.c b/opencl/api/opencl/khronos/icd/icd.c index c32a7841d7..fdeff798fc 100644 --- a/opencl/api/opencl/khronos/icd/icd.c +++ b/opencl/api/opencl/khronos/icd/icd.c @@ -58,6 +58,7 @@ void khrIcdVendorAdd(const char *libraryName) cl_uint i = 0; cl_uint platformCount = 0; cl_platform_id *platforms = NULL; + KHRicdVendor *vendorIterator = NULL; // require that the library name be valid if (!libraryName) @@ -74,6 +75,16 @@ void khrIcdVendorAdd(const char *libraryName) goto Done; } + // ensure that we haven't already loaded this vendor + for (vendorIterator = khrIcdVendors; vendorIterator; vendorIterator = vendorIterator->next) + { + if (vendorIterator->library == library) + { + KHR_ICD_TRACE("already loaded vendor %s, nothing to do here\n", libraryName); + goto Done; + } + } + // get the library's clGetExtensionFunctionAddress pointer p_clGetExtensionFunctionAddress = (pfn_clGetExtensionFunctionAddress)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clGetExtensionFunctionAddress"); if (!p_clGetExtensionFunctionAddress) diff --git a/opencl/api/opencl/khronos/icd/icd.h b/opencl/api/opencl/khronos/icd/icd.h index aa6a308cc3..9221be4709 100644 --- a/opencl/api/opencl/khronos/icd/icd.h +++ b/opencl/api/opencl/khronos/icd/icd.h @@ -53,6 +53,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + /* * type definitions */ @@ -145,7 +149,16 @@ void khrIcdContextPropertiesGetPlatform( fprintf(stderr, "KHR ICD trace at %s:%d: ", __FILE__, __LINE__); \ fprintf(stderr, __VA_ARGS__); \ } while (0) - +#ifdef _WIN32 +#define KHR_ICD_WIDE_TRACE(...) \ + do \ + { \ + fwprintf(stderr, L"KHR ICD trace at %hs:%d: ", __FILE__, __LINE__); \ + fwprintf(stderr, __VA_ARGS__); \ + } while (0) +#else +#define KHR_ICD_WIDE_TRACE(...) +#endif #define KHR_ICD_ASSERT(x) \ do \ { \ @@ -156,6 +169,7 @@ void khrIcdContextPropertiesGetPlatform( } while (0) #else #define KHR_ICD_TRACE(...) + #define KHR_ICD_WIDE_TRACE(...) #define KHR_ICD_ASSERT(x) #endif diff --git a/opencl/api/opencl/khronos/icd/icd_windows.c b/opencl/api/opencl/khronos/icd/icd_windows.c index 98252648fc..13e3e5f94b 100644 --- a/opencl/api/opencl/khronos/icd/icd_windows.c +++ b/opencl/api/opencl/khronos/icd/icd_windows.c @@ -36,6 +36,7 @@ */ #include "icd.h" +#include "icd_windows_hkr.h" #include #include #include @@ -57,6 +58,11 @@ BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVO HKEY platformsKey = NULL; DWORD dwIndex; + if (!khrIcdOsVendorsEnumerateHKR()) + { + KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n"); + } + KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName); result = RegOpenKeyExA( HKEY_LOCAL_MACHINE, diff --git a/opencl/api/opencl/khronos/icd/icd_windows_hkr.c b/opencl/api/opencl/khronos/icd/icd_windows_hkr.c new file mode 100644 index 0000000000..076b60f5ad --- /dev/null +++ b/opencl/api/opencl/khronos/icd/icd_windows_hkr.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2017 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software source and associated documentation files (the "Materials"), + * to deal in the Materials without restriction, including without limitation + * the rights to use, copy, modify, compile, merge, publish, distribute, + * sublicense, and/or sell copies of the Materials, and to permit persons to + * whom the Materials are furnished to do so, subject the following terms and + * conditions: + * + * All modifications to the Materials used to create a binary that is + * distributed to third parties shall be provided to Khronos with an + * unrestricted license to use for the purposes of implementing bug fixes and + * enhancements to the Materials; + * + * If the binary is used as part of an OpenCL(TM) implementation, whether binary + * is distributed together with or separately to that implementation, then + * recipient must become an OpenCL Adopter and follow the published OpenCL + * conformance process for that implementation, details at: + * http://www.khronos.org/conformance/; + * + * The above copyright notice, the OpenCL trademark license, and this permission + * notice shall be included in all copies or substantial portions of the + * Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN + * THE MATERIALS. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include "icd.h" +#include "icd_windows_hkr.h" +#include +#include +#include +#include +#include +#include +#include + + // This GUID was only added to devguid.h on Windows SDK v10.0.16232 which + // corresponds to Windows 10 Redstone 3 (Windows 10 Fall Creators Update). +DEFINE_GUID(OCL_GUID_DEVCLASS_SOFTWARECOMPONENT, 0x5c4c3332, 0x344d, 0x483c, 0x87, 0x39, 0x25, 0x9e, 0x93, 0x4c, 0x9c, 0xc8); + +typedef enum +{ + ProbeFailure, + PendingReboot, + Valid +} DeviceProbeResult; + +#define KHR_SAFE_RELEASE(mem) \ + do \ + { \ + free(mem); \ + mem = NULL; \ + } while (0) + +#ifdef _WIN64 +static const char OPENCL_REG_SUB_KEY[] = "OpenCLDriverName"; +#else +static const char OPENCL_REG_SUB_KEY[] = "OpenCLDriverNameWow"; +#endif + +static bool ReadOpenCLKey(DEVINST dnDevNode) +{ + HKEY hkey = 0; + CONFIGRET ret; + bool bRet = false; + DWORD dwLibraryNameType = 0; + char *cszOclPath = NULL; + DWORD dwOclPathSize = 0; + LSTATUS result; + + ret = CM_Open_DevNode_Key( + dnDevNode, + KEY_QUERY_VALUE, + 0, + RegDisposition_OpenExisting, + &hkey, + CM_REGISTRY_SOFTWARE); + + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE("Failed with ret 0x%x\n", ret); + goto out; + } + else + { + result = RegQueryValueExA( + hkey, + OPENCL_REG_SUB_KEY, + NULL, + &dwLibraryNameType, + NULL, + &dwOclPathSize); + + if (ERROR_SUCCESS != result) + { + KHR_ICD_TRACE("Failed to open sub key 0x%x\n", result); + goto out; + } + + cszOclPath = malloc(dwOclPathSize); + if (NULL == cszOclPath) + { + KHR_ICD_TRACE("Failed to allocate %u bytes for registry value\n", dwOclPathSize); + goto out; + } + + result = RegQueryValueExA( + hkey, + OPENCL_REG_SUB_KEY, + NULL, + &dwLibraryNameType, + (LPBYTE)cszOclPath, + &dwOclPathSize); + if (ERROR_SUCCESS != result) + { + KHR_ICD_TRACE("Failed to open sub key 0x%x\n", result); + goto out; + } + + if (REG_SZ != dwLibraryNameType) + { + KHR_ICD_TRACE("Unexpected registry entry 0x%x! continuing\n", dwLibraryNameType); + goto out; + } + + KHR_ICD_TRACE(" Path: %s\n", cszOclPath); + + khrIcdVendorAdd(cszOclPath); + + bRet = true; + } + +out: + free(cszOclPath); + + if (hkey) + { + result = RegCloseKey(hkey); + if (ERROR_SUCCESS != result) + { + KHR_ICD_TRACE("WARNING: failed to close hkey 0x%x\n", result); + } + } + + return bRet; +} + +static DeviceProbeResult ProbeDevice(DEVINST devnode) +{ + CONFIGRET ret; + ULONG ulStatus; + ULONG ulProblem; + + ret = CM_Get_DevNode_Status( + &ulStatus, + &ulProblem, + devnode, + 0); + + // TODO: consider extracting warning messages out of this function + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE(" WARNING: failed to probe the status of the device 0x%x\n", ret); + return ProbeFailure; + } + + // + // Careful here, we need to check 2 scenarios: + // 1. DN_NEED_RESTART + // status flag indicates that a reboot is needed when an _already started_ + // device cannot be stopped. This covers devices that are still started with their + // old KMD (because they couldn't be stopped/restarted) while the UMD is updated + // and possibly out of sync. + // + // 2. Status & DN_HAS_PROBLEM && Problem == CM_PROB_NEED_RESTART + // indicates that a reboot is needed when a _stopped device_ cannot be (re)started. + // + if (((ulStatus & DN_HAS_PROBLEM) && ulProblem == CM_PROB_NEED_RESTART) || + ulStatus & DN_NEED_RESTART) + { + KHR_ICD_TRACE(" WARNING: device is pending reboot (0x%x), skipping...\n", ulStatus); + return PendingReboot; + } + + return Valid; +} + +// Tries to look for the OpenCL key under the display devices and +// if not found, falls back to software component devices. +bool khrIcdOsVendorsEnumerateHKR(void) +{ + CONFIGRET ret; + int iret; + bool foundOpenCLKey = false; + DEVINST devinst = 0; + DEVINST devchild = 0; + wchar_t *deviceIdList = NULL; + ULONG szBuffer = 0; + + OLECHAR display_adapter_guid_str[MAX_GUID_STRING_LEN]; + ULONG ulFlags = CM_GETIDLIST_FILTER_CLASS | + CM_GETIDLIST_FILTER_PRESENT; + + iret = StringFromGUID2( + &GUID_DEVCLASS_DISPLAY, + display_adapter_guid_str, + MAX_GUID_STRING_LEN); + + if (MAX_GUID_STRING_LEN != iret) + { + KHR_ICD_TRACE("StringFromGUID2 failed with %d\n", iret); + goto out; + } + + // Paranoia: we might have a new device added to the list between the call + // to CM_Get_Device_ID_List_Size() and the call to CM_Get_Device_ID_List(). + do + { + ret = CM_Get_Device_ID_List_SizeW( + &szBuffer, + display_adapter_guid_str, + ulFlags); + + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE("CM_Get_Device_ID_List_size failed with 0x%x\n", ret); + break; + } + + // "pulLen [out] Receives a value representing the required buffer + // size, in characters." + // So we need to allocate the right size in bytes but we still need + // to keep szBuffer as it was returned from CM_Get_Device_ID_List_Size so + // the call to CM_Get_Device_ID_List will receive the correct size. + deviceIdList = malloc(szBuffer * sizeof(wchar_t)); + if (NULL == deviceIdList) + { + KHR_ICD_TRACE("Failed to allocate %u bytes for device ID strings\n", szBuffer); + break; + } + + ret = CM_Get_Device_ID_ListW( + display_adapter_guid_str, + deviceIdList, + szBuffer, + ulFlags); + + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE("CM_Get_Device_ID_List failed with 0x%x\n", ret); + KHR_SAFE_RELEASE(deviceIdList); + } + } while (CR_BUFFER_SMALL == ret); + + if (NULL == deviceIdList) + { + goto out; + } + + for (PWSTR deviceId = deviceIdList; *deviceId; deviceId += wcslen(deviceId) + 1) + { + DEVPROPTYPE devpropType; + + KHR_ICD_WIDE_TRACE(L"Device ID: %ls\n", deviceId); + + ret = CM_Locate_DevNodeW(&devinst, deviceId, 0); + if (CR_SUCCESS == ret) + { + KHR_ICD_TRACE(" devinst: %d\n", devinst); + } + else + { + KHR_ICD_TRACE("CM_Locate_DevNode failed with 0x%x\n", ret); + continue; + } + + if (ProbeDevice(devinst) != Valid) + { + continue; + } + + KHR_ICD_TRACE(" Trying to look for the key in the display adapter HKR...\n"); + if (ReadOpenCLKey(devinst)) + { + foundOpenCLKey = true; + continue; + } + + KHR_ICD_TRACE(" Could not find the key, proceeding to children software components...\n"); + + ret = CM_Get_Child( + &devchild, + devinst, + 0); + + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE(" CM_Get_Child returned 0x%x, skipping children...\n", ret); + } + else + { + do + { + wchar_t deviceInstanceID[MAX_DEVICE_ID_LEN] = { 0 }; + GUID guid; + ULONG szGuid = sizeof(guid); + + KHR_ICD_TRACE(" devchild: %d\n", devchild); + ret = CM_Get_Device_IDW( + devchild, + deviceInstanceID, + sizeof(deviceInstanceID), + 0); + + if (CR_SUCCESS != ret) + { + KHR_ICD_TRACE(" CM_Get_Device_ID returned 0x%x, skipping device...\n", ret); + continue; + } + else + { + KHR_ICD_WIDE_TRACE(L" deviceInstanceID: %ls\n", deviceInstanceID); + } + + ret = CM_Get_DevNode_PropertyW( + devchild, + &DEVPKEY_Device_ClassGuid, + &devpropType, + (PBYTE)&guid, + &szGuid, + 0); + + KHR_ICD_ASSERT(devpropType == DEVPROP_TYPE_GUID); + + if (CR_SUCCESS != ret || + !IsEqualGUID(&OCL_GUID_DEVCLASS_SOFTWARECOMPONENT, &guid)) + { + continue; + } + + if (ProbeDevice(devchild) != Valid) + { + continue; + } + + if (ReadOpenCLKey(devchild)) + { + foundOpenCLKey = true; + break; + } + } while (CM_Get_Sibling(&devchild, devchild, 0) == CR_SUCCESS); + } + } + +out: + free(deviceIdList); + return foundOpenCLKey; +} diff --git a/opencl/api/opencl/khronos/icd/icd_windows_hkr.h b/opencl/api/opencl/khronos/icd/icd_windows_hkr.h new file mode 100644 index 0000000000..b10d15a579 --- /dev/null +++ b/opencl/api/opencl/khronos/icd/icd_windows_hkr.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software source and associated documentation files (the "Materials"), + * to deal in the Materials without restriction, including without limitation + * the rights to use, copy, modify, compile, merge, publish, distribute, + * sublicense, and/or sell copies of the Materials, and to permit persons to + * whom the Materials are furnished to do so, subject the following terms and + * conditions: + * + * All modifications to the Materials used to create a binary that is + * distributed to third parties shall be provided to Khronos with an + * unrestricted license to use for the purposes of implementing bug fixes and + * enhancements to the Materials; + * + * If the binary is used as part of an OpenCL(TM) implementation, whether binary + * is distributed together with or separately to that implementation, then + * recipient must become an OpenCL Adopter and follow the published OpenCL + * conformance process for that implementation, details at: + * http://www.khronos.org/conformance/; + * + * The above copyright notice, the OpenCL trademark license, and this permission + * notice shall be included in all copies or substantial portions of the + * Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS IN + * THE MATERIALS. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include + +bool khrIcdOsVendorsEnumerateHKR(void);