Windows 10 RS4 Support for the OpenCL ICD Loader w/ Build Option (#78)
authorBen Ashbaugh <ben.ashbaugh@intel.com>
Mon, 1 Jul 2019 12:53:41 +0000 (05:53 -0700)
committerKedar Patil <kepatil@nvidia.com>
Mon, 1 Jul 2019 12:53:41 +0000 (18:23 +0530)
* Windows 10 RS4 support for OpenCL ICD as per MS directive

Motivation - MS is adopting DCHU complaince and for For RS4 it will be mandatory for OpenCL to load via registry keys contained only within the HKR section of the registry as writes outside of HKR will not be allowed for the INF. It is also to support ParaV feature of the OS to make it "virtualization-ready".

* Update Copyright year
* Fix vendors enumeration on 32-bit Windows OS
* Update CMake file for detecting necessary includes for the Windows WDK
* Add option to build with or without the WDK (default: with)
* Documented Windows WDK dependency

CMakeLists.txt
README.md
loader/windows/OpenCL.rc
loader/windows/icd_windows.c
loader/windows/icd_windows_dxgk.c [new file with mode: 0644]
loader/windows/icd_windows_dxgk.h [new file with mode: 0644]
loader/windows/icd_windows_hkr.c

index 4ecede472ae583dbcc24602809dd7021a5ddb541..b3f8c0b39d729c2e905bbee5a243dfe62ff3b9cd 100644 (file)
@@ -41,6 +41,7 @@ if (WIN32)
     list (APPEND OPENCL_ICD_LOADER_SOURCES 
         loader/windows/icd_windows.c
         loader/windows/icd_windows_hkr.c
+        loader/windows/icd_windows_dxgk.c
         loader/windows/OpenCL.def
         loader/windows/OpenCL.rc)
     # Only add the DXSDK include directory if the environment variable is
@@ -62,6 +63,29 @@ set_target_properties (OpenCL PROPERTIES VERSION "1.2" SOVERSION "1")
 
 if (WIN32)
     target_link_libraries (OpenCL cfgmgr32.lib)
+
+    option (OPENCL_ICD_LOADER_REQUIRE_WDK "Build with D3DKMT support, which requires the Windows WDK." ON)
+    if (OPENCL_ICD_LOADER_REQUIRE_WDK)
+        if(DEFINED ENV{WDKContentRoot})
+            file(GLOB D3DKMT_HEADER "$ENV{WDKContentRoot}/Include/*/km/d3dkmthk.h")
+        else()
+            file(GLOB D3DKMT_HEADER "$ENV{HOMEDRIVE}/Program Files */Windows Kits/10/Include/*/km/d3dkmthk.h")
+        endif()
+
+        if(D3DKMT_HEADER)
+            list(GET D3DKMT_HEADER -1 LATEST_D3DKMT_HEADER)
+            get_filename_component(WDK_DIRECTORY ${LATEST_D3DKMT_HEADER} DIRECTORY)
+            get_filename_component(WDK_DIRECTORY ${WDK_DIRECTORY} DIRECTORY)
+            message(STATUS "Found the Windows WDK in: ${WDK_DIRECTORY}")
+            target_compile_definitions(OpenCL PRIVATE OPENCL_ICD_LOADER_REQUIRE_WDK)
+            target_include_directories(OpenCL PRIVATE ${WDK_DIRECTORY}/um)
+            target_include_directories(OpenCL PRIVATE ${WDK_DIRECTORY}/km)
+            target_include_directories(OpenCL PRIVATE ${WDK_DIRECTORY}/shared)
+        else()
+            message(FATAL_ERROR "The Windows WDK was not found. Consider disabling OPENCL_ICD_LOADER_REQUIRE_WDK. Aborting.")
+        endif()
+    endif()
+
     if(NOT USE_DYNAMIC_VCXX_RUNTIME)
         string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
         string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
index 4493430e618bd4a343e8be9360bc57875c14cfbb..27c1de719137b7b6ae01d851b50d5e548b1de592 100644 (file)
--- a/README.md
+++ b/README.md
@@ -30,6 +30,10 @@ The OpenCL ICD Loader requires OpenCL Headers.
 To use system OpenCL Headers, please specify the OpenCL Header location using the CMake variable `OPENCL_ICD_LOADER_HEADERS_DIR`.
 By default, the OpenCL ICD Loader will look for OpenCL Headers in the `inc` directory.
 
+By default, the OpenCL ICD Loader on Windows requires the Windows Driver Kit (WDK).
+An OpenCL ICD Loader may be built without the Windows Driver Kit using the CMake variable `OPENCL_ICD_LOADER_REQUIRE_WDK`, however this option should be used with caution since it may prevent the OpenCL ICD Loader from enumerating some OpenCL implementations.
+This dependency may be removed in the future.
+
 The OpenCL ICD Loader uses CMake for its build system.
 If CMake is not provided by your build system or OS package manager, please consult the [CMake website](https://cmake.org).
 
index 561e6ba26f28c90283b00c47b2793ca9843dbc54..330da28917e83e815d8907be63472a31c0130233 100644 (file)
 
 #include <windows.h>
 
+#define OPENCL_ICD_LOADER_VERSION_MAJOR 2
+#define OPENCL_ICD_LOADER_VERSION_MINOR 2
+#define OPENCL_ICD_LOADER_VERSION_REV   2
+
 #ifdef RC_INVOKED
 
+#define OPENCL_ICD_LOADER_VAL(_v) #_v
+#define OPENCL_ICD_LOADER_TOSTRING(_d) OPENCL_ICD_LOADER_VAL(_d)
+#define OPENCL_ICD_LOADER_VERSION_STRING \
+    OPENCL_ICD_LOADER_TOSTRING(OPENCL_ICD_LOADER_VERSION_MAJOR) "." \
+    OPENCL_ICD_LOADER_TOSTRING(OPENCL_ICD_LOADER_VERSION_MINOR) "." \
+    OPENCL_ICD_LOADER_TOSTRING(OPENCL_ICD_LOADER_VERSION_REV)
+
 VS_VERSION_INFO VERSIONINFO
-FILEVERSION    2,2,1,0
-PRODUCTVERSION 2,2,1,0
+FILEVERSION    OPENCL_ICD_LOADER_VERSION_MAJOR,OPENCL_ICD_LOADER_VERSION_MINOR,OPENCL_ICD_LOADER_VERSION_REV,0
+PRODUCTVERSION OPENCL_ICD_LOADER_VERSION_MAJOR,OPENCL_ICD_LOADER_VERSION_MINOR,OPENCL_ICD_LOADER_VERSION_REV,0
 FILETYPE       VFT_DLL
 
 BEGIN
@@ -31,9 +42,9 @@ BEGIN
         BLOCK "040904E4"
         BEGIN
             VALUE "FileDescription" ,"OpenCL Client DLL"
-            VALUE "ProductName"     ,"Khronos OpenCL ICD"
+            VALUE "ProductName"     ,"Khronos OpenCL ICD Loader"
             VALUE "LegalCopyright"  ,"Copyright \251 The Khronos Group Inc 2016-2019"
-            VALUE "FileVersion"     ,"2.2.1.0"
+            VALUE "FileVersion"     ,OPENCL_ICD_LOADER_VERSION_STRING ".0"
             VALUE "CompanyName"     ,"Khronos Group"
             VALUE "InternalName"    ,"OpenCL"
             VALUE "OriginalFilename","OpenCL.dll"
index 5f890852e27242e7649479ddc189947207245af9..ec86184b93ed13e74f970e33a6cd24a94db856e8 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "icd.h"
 #include "icd_windows_hkr.h"
+#include "icd_windows_dxgk.h"
 #include <stdio.h>
 #include <windows.h>
 #include <winreg.h>
@@ -39,9 +40,13 @@ BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVO
     HKEY platformsKey = NULL;
     DWORD dwIndex;
 
-    if (!khrIcdOsVendorsEnumerateHKR())
+    if (!khrIcdOsVendorsEnumerateDXGK())
     {
-        KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
+        KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
+        if (!khrIcdOsVendorsEnumerateHKR())
+        {
+            KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
+        }
     }
 
     KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName);
diff --git a/loader/windows/icd_windows_dxgk.c b/loader/windows/icd_windows_dxgk.c
new file mode 100644 (file)
index 0000000..8cc3fb9
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#include "icd.h"
+#include "icd_windows_dxgk.h"
+
+#if defined(OPENCL_ICD_LOADER_REQUIRE_WDK)
+#include <windows.h>
+
+#ifndef NTSTATUS
+typedef LONG NTSTATUS;
+#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
+#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
+#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+#endif
+
+#include <d3dkmthk.h>
+#endif
+
+bool khrIcdOsVendorsEnumerateDXGK(void)
+{
+    bool ret = false;
+#if defined(OPENCL_ICD_LOADER_REQUIRE_WDK)
+#if defined(DXGKDDI_INTERFACE_VERSION_WDDM2_4) && (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_4)
+    {
+        D3DKMT_ADAPTERINFO* pAdapterInfo = NULL;
+        D3DKMT_ENUMADAPTERS2 EnumAdapters;
+        NTSTATUS Status = STATUS_SUCCESS;
+
+        // Get handle to GDI Runtime
+        HMODULE h = LoadLibrary("gdi32.dll");
+        KHR_ICD_ASSERT(h != NULL);
+
+        char cszLibraryName[MAX_PATH] = { 0 };
+        PFND3DKMT_ENUMADAPTERS2 pEnumAdapters2 = (PFND3DKMT_ENUMADAPTERS2)GetProcAddress((HMODULE)h, "D3DKMTEnumAdapters2");
+        if (!pEnumAdapters2)
+        {
+            KHR_ICD_TRACE("GetProcAddress failed for D3DKMT_ENUMADAPTERS2\n");
+            goto out;
+        }
+        while (1)
+        {
+            EnumAdapters.NumAdapters = 0;
+            EnumAdapters.pAdapters = NULL;
+            Status = pEnumAdapters2(&EnumAdapters);
+            if (Status == STATUS_BUFFER_TOO_SMALL)
+            {
+                // Number of Adapters increased between calls, retry;
+                continue;
+            }
+            else if (!NT_SUCCESS(Status))
+            {
+                KHR_ICD_TRACE("D3DKMT_ENUMADAPTERS2 status != SUCCESS\n");
+                goto out;
+            }
+            break;
+        }
+        pAdapterInfo = (D3DKMT_ADAPTERINFO*)malloc(sizeof(D3DKMT_ADAPTERINFO)*(EnumAdapters.NumAdapters));
+        if (pAdapterInfo == NULL)
+        {
+            KHR_ICD_TRACE("Allocation failure for AdapterInfo buffer\n");
+            goto out;
+        }
+        EnumAdapters.pAdapters = pAdapterInfo;
+        Status = pEnumAdapters2(&EnumAdapters);
+        if (!NT_SUCCESS(Status))
+        {
+            KHR_ICD_TRACE("D3DKMT_ENUMADAPTERS2 status != SUCCESS\n");
+            goto out;
+        }
+        for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.NumAdapters; AdapterIndex++)
+        {
+            D3DDDI_QUERYREGISTRY_INFO QueryArgs = {0};
+            D3DDDI_QUERYREGISTRY_INFO* pQueryArgs = &QueryArgs;
+            D3DDDI_QUERYREGISTRY_INFO* pQueryBuffer = NULL;
+            QueryArgs.QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY;
+            QueryArgs.QueryFlags.TranslatePath = TRUE;
+            QueryArgs.ValueType = REG_SZ;
+#ifdef _WIN64
+            wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverName"), L"OpenCLDriverName");
+#else
+            // There is no WOW prefix for 32bit Windows hence make a specific check
+            BOOL is_wow64;
+            if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
+            {
+                wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverNameWow"), L"OpenCLDriverNameWow");
+            }
+            else
+            {
+                wcscpy_s(QueryArgs.ValueName, ARRAYSIZE(L"OpenCLDriverName"), L"OpenCLDriverName");
+            }
+#endif
+            D3DKMT_QUERYADAPTERINFO QueryAdapterInfo = {0};
+            QueryAdapterInfo.hAdapter = pAdapterInfo[AdapterIndex].hAdapter;
+            QueryAdapterInfo.Type = KMTQAITYPE_QUERYREGISTRY;
+            QueryAdapterInfo.pPrivateDriverData = &QueryArgs;
+            QueryAdapterInfo.PrivateDriverDataSize = sizeof(QueryArgs);
+            Status = D3DKMTQueryAdapterInfo(&QueryAdapterInfo);
+            if (!NT_SUCCESS(Status))
+            {
+                KHR_ICD_TRACE("D3DKMT_QUERYADAPTERINFO status != SUCCESS\n");
+                goto out;
+            }
+            if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
+            {
+                ULONG QueryBufferSize = sizeof(D3DDDI_QUERYREGISTRY_INFO) + QueryArgs.OutputValueSize;
+                pQueryBuffer = (D3DDDI_QUERYREGISTRY_INFO*)malloc(QueryBufferSize);
+                memcpy(pQueryBuffer, &QueryArgs, sizeof(D3DDDI_QUERYREGISTRY_INFO));
+                QueryAdapterInfo.pPrivateDriverData = pQueryBuffer;
+                QueryAdapterInfo.PrivateDriverDataSize = QueryBufferSize;
+                Status = D3DKMTQueryAdapterInfo(&QueryAdapterInfo);
+                pQueryArgs = pQueryBuffer;
+            }
+            if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
+            {
+                wchar_t* pWchar = pQueryArgs->OutputString;
+                memset(cszLibraryName, 0, sizeof(cszLibraryName));
+                {
+                    size_t len = wcstombs(cszLibraryName, pWchar, sizeof(cszLibraryName));
+                    KHR_ICD_ASSERT(len == (sizeof(cszLibraryName) - 1));
+                    khrIcdVendorAdd(cszLibraryName);
+                }
+            }
+            else if (Status == STATUS_INVALID_PARAMETER && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_FAIL)
+            {
+                free(pQueryBuffer);
+                goto out;
+            }
+            free(pQueryBuffer);
+        }
+        ret = true;
+out:
+      free(pAdapterInfo);
+      FreeLibrary(h);
+    }
+#endif
+#endif
+    return ret;
+}
diff --git a/loader/windows/icd_windows_dxgk.h b/loader/windows/icd_windows_dxgk.h
new file mode 100644 (file)
index 0000000..f6cb65d
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017-2019 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#include <stdbool.h>
+
+bool khrIcdOsVendorsEnumerateDXGK(void);
index 6003f2c272485a9269e070489c0a48e5cc601f39..338718143c7004d2797b5662b1d7bfeffde273b2 100644 (file)
@@ -117,7 +117,7 @@ static bool ReadOpenCLKey(DEVINST dnDevNode)
 
         result = RegQueryValueExA(
             hkey,
-            OPENCL_REG_SUB_KEY,
+            GetOpenCLRegKeyName(),
             NULL,
             &dwLibraryNameType,
             (LPBYTE)cszOclPath,