Skip to content

Commit

Permalink
remove WDK dependency for OpenCL ICD loader (#102)
Browse files Browse the repository at this point in the history
* remove dependency on Windows WDK for Windows ICD Loader builds

After this change, instead of including a WDK header file, a
private header file is used with just the definitions needed
for the ICD loader.  The header file is copied unchanged from
the Vulkan loader repo.

* update README to remove WDK dependency

* updated file version to v2.2.8
  • Loading branch information
bashbaug committed Apr 23, 2020
1 parent 47f05fa commit fe09ad1
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 97 deletions.
23 changes: 1 addition & 22 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set (OPENCL_ICD_LOADER_SOURCES

if (WIN32)
list (APPEND OPENCL_ICD_LOADER_SOURCES
loader/windows/adapter.h
loader/windows/icd_windows.c
loader/windows/icd_windows.h
loader/windows/icd_windows_dxgk.c
Expand Down Expand Up @@ -82,28 +83,6 @@ set_target_properties (OpenCL PROPERTIES VERSION "1.2" SOVERSION "1")
if (WIN32)
target_link_libraries (OpenCL cfgmgr32.lib RuntimeObject.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}")
Expand Down
9 changes: 0 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@ 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).
To build OpenCL ICD Loader with WDK support -
* Install recent Windows WDK currently at https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk

* Establish environment variable WDK to include directory. Ex: set WDK=C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0

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).

Expand Down
6 changes: 3 additions & 3 deletions loader/windows/OpenCL.rc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2019 The Khronos Group Inc.
* Copyright (c) 2016-2020 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.
Expand All @@ -20,7 +20,7 @@

#define OPENCL_ICD_LOADER_VERSION_MAJOR 2
#define OPENCL_ICD_LOADER_VERSION_MINOR 2
#define OPENCL_ICD_LOADER_VERSION_REV 7
#define OPENCL_ICD_LOADER_VERSION_REV 8

#ifdef RC_INVOKED

Expand All @@ -43,7 +43,7 @@ BEGIN
BEGIN
VALUE "FileDescription" ,"OpenCL Client DLL"
VALUE "ProductName" ,"Khronos OpenCL ICD Loader"
VALUE "LegalCopyright" ,"Copyright \251 The Khronos Group Inc 2016-2019"
VALUE "LegalCopyright" ,"Copyright \251 The Khronos Group Inc 2016-2020"
VALUE "FileVersion" ,OPENCL_ICD_LOADER_VERSION_STRING ".0"
VALUE "CompanyName" ,"Khronos Group"
VALUE "InternalName" ,"OpenCL"
Expand Down
80 changes: 80 additions & 0 deletions loader/windows/adapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2019 The Khronos Group Inc.
* Copyright (c) 2019 Valve Corporation
* Copyright (c) 2019 LunarG, 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.
*
* Author: Lenny Komow <lenny@lunarg.com>
*/

typedef struct LoaderEnumAdapters2 {
ULONG adapter_count;
struct {
UINT handle;
LUID luid;
ULONG source_count;
BOOL present_move_regions_preferred;
} * adapters;
} LoaderEnumAdapters2;

typedef _Check_return_ NTSTATUS(APIENTRY *PFN_LoaderEnumAdapters2)(const LoaderEnumAdapters2 *);

typedef enum AdapterInfoType {
LOADER_QUERY_TYPE_REGISTRY = 48,
} AdapterInfoType;

typedef struct LoaderQueryAdapterInfo {
UINT handle;
AdapterInfoType type;
VOID *private_data;
UINT private_data_size;
} LoaderQueryAdapterInfo;

typedef _Check_return_ NTSTATUS(APIENTRY *PFN_LoaderQueryAdapterInfo)(const LoaderQueryAdapterInfo *);

typedef enum LoaderQueryRegistryType {
LOADER_QUERY_REGISTRY_ADAPTER_KEY = 1,
} LoaderQueryRegistryType;

typedef enum LoaderQueryRegistryStatus {
LOADER_QUERY_REGISTRY_STATUS_SUCCESS = 0,
LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW = 1,
} LoaderQueryRegistryStatus;

typedef struct LoaderQueryRegistryFlags {
union {
struct {
UINT translate_path : 1;
UINT mutable_value : 1;
UINT reserved : 30;
};
UINT value;
};
} LoaderQueryRegistryFlags;

typedef struct LoaderQueryRegistryInfo {
LoaderQueryRegistryType query_type;
LoaderQueryRegistryFlags query_flags;
WCHAR value_name[MAX_PATH];
ULONG value_type;
ULONG physical_adapter_index;
ULONG output_value_size;
LoaderQueryRegistryStatus status;
union {
DWORD output_dword;
UINT64 output_qword;
WCHAR output_string[1];
BYTE output_binary[1];
};
} LoaderQueryRegistryInfo;
125 changes: 62 additions & 63 deletions loader/windows/icd_windows_dxgk.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2019 The Khronos Group Inc.
* Copyright (c) 2017-2020 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.
Expand All @@ -19,109 +19,109 @@
#include "icd.h"
#include "icd_windows_dxgk.h"

#if defined(OPENCL_ICD_LOADER_REQUIRE_WDK)
#include <windows.h>
#include "adapter.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>
#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
#endif

bool khrIcdOsVendorsEnumerateDXGK(void)
{
bool ret = false;
int result = 0;
#if defined(OPENCL_ICD_LOADER_REQUIRE_WDK)
#if defined(DXGKDDI_INTERFACE_VERSION_WDDM2_4) && (DXGKDDI_INTERFACE_VERSION >= DXGKDDI_INTERFACE_VERSION_WDDM2_4)

// Get handle to GDI Runtime
HMODULE h = LoadLibrary("gdi32.dll");
if (h == NULL)
return ret;

if(GetProcAddress((HMODULE)h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
if(GetProcAddress(h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
{
D3DKMT_ADAPTERINFO* pAdapterInfo = NULL;
D3DKMT_ENUMADAPTERS2 EnumAdapters;
NTSTATUS Status = STATUS_SUCCESS;
LoaderEnumAdapters2 EnumAdapters;
NTSTATUS status = STATUS_SUCCESS;

char cszLibraryName[MAX_PATH] = { 0 };
EnumAdapters.NumAdapters = 0;
EnumAdapters.pAdapters = NULL;
PFND3DKMT_ENUMADAPTERS2 pEnumAdapters2 = (PFND3DKMT_ENUMADAPTERS2)GetProcAddress((HMODULE)h, "D3DKMTEnumAdapters2");
EnumAdapters.adapter_count = 0;
EnumAdapters.adapters = NULL;
PFN_LoaderEnumAdapters2 pEnumAdapters2 = (PFN_LoaderEnumAdapters2)GetProcAddress(h, "D3DKMTEnumAdapters2");
if (!pEnumAdapters2)
{
KHR_ICD_TRACE("GetProcAddress failed for D3DKMT_ENUMADAPTERS2\n");
KHR_ICD_TRACE("GetProcAddress failed for D3DKMTEnumAdapters2\n");
goto out;
}
PFN_LoaderQueryAdapterInfo pQueryAdapterInfo = (PFN_LoaderQueryAdapterInfo)GetProcAddress(h, "D3DKMTQueryAdapterInfo");
if (!pQueryAdapterInfo)
{
KHR_ICD_TRACE("GetProcAddress failed for D3DKMTQueryAdapterInfo\n");
goto out;
}
while (1)
{
EnumAdapters.NumAdapters = 0;
EnumAdapters.pAdapters = NULL;
Status = pEnumAdapters2(&EnumAdapters);
if (Status == STATUS_BUFFER_TOO_SMALL)
EnumAdapters.adapter_count = 0;
EnumAdapters.adapters = NULL;
status = pEnumAdapters2(&EnumAdapters);
if (status == STATUS_BUFFER_TOO_SMALL)
{
// Number of Adapters increased between calls, retry;
continue;
}
else if (!NT_SUCCESS(Status))
else if (!NT_SUCCESS(status))
{
KHR_ICD_TRACE("D3DKMT_ENUMADAPTERS2 status != SUCCESS\n");
KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
goto out;
}
break;
}
pAdapterInfo = (D3DKMT_ADAPTERINFO*)malloc(sizeof(D3DKMT_ADAPTERINFO)*(EnumAdapters.NumAdapters));
if (pAdapterInfo == NULL)
EnumAdapters.adapters = malloc(sizeof(*EnumAdapters.adapters)*(EnumAdapters.adapter_count));
if (EnumAdapters.adapters == NULL)
{
KHR_ICD_TRACE("Allocation failure for AdapterInfo buffer\n");
KHR_ICD_TRACE("Allocation failure for adapters buffer\n");
goto out;
}
EnumAdapters.pAdapters = pAdapterInfo;
Status = pEnumAdapters2(&EnumAdapters);
if (!NT_SUCCESS(Status))
status = pEnumAdapters2(&EnumAdapters);
if (!NT_SUCCESS(status))
{
KHR_ICD_TRACE("D3DKMT_ENUMADAPTERS2 status != SUCCESS\n");
KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
goto out;
}
const char* cszOpenCLRegKeyName = getOpenCLRegKeyName();
const int szOpenCLRegKeyName = (int)(strlen(cszOpenCLRegKeyName) + 1)*sizeof(cszOpenCLRegKeyName[0]);
for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.NumAdapters; AdapterIndex++)
for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.adapter_count; 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;
LoaderQueryRegistryInfo queryArgs = {0};
LoaderQueryRegistryInfo* pQueryArgs = &queryArgs;
LoaderQueryRegistryInfo* pQueryBuffer = NULL;
queryArgs.query_type = LOADER_QUERY_REGISTRY_ADAPTER_KEY;
queryArgs.query_flags.translate_path = TRUE;
queryArgs.value_type = REG_SZ;
result = MultiByteToWideChar(
CP_ACP,
0,
cszOpenCLRegKeyName,
szOpenCLRegKeyName,
queryArgs.ValueName,
ARRAYSIZE(queryArgs.ValueName));
queryArgs.value_name,
ARRAYSIZE(queryArgs.value_name));
if (!result)
{
KHR_ICD_TRACE("MultiByteToWideChar status != SUCCESS\n");
continue;
}
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))
LoaderQueryAdapterInfo queryAdapterInfo = {0};
queryAdapterInfo.handle = EnumAdapters.adapters[AdapterIndex].handle;
queryAdapterInfo.type = LOADER_QUERY_TYPE_REGISTRY;
queryAdapterInfo.private_data = &queryArgs;
queryAdapterInfo.private_data_size = sizeof(queryArgs);
status = pQueryAdapterInfo(&queryAdapterInfo);
if (!NT_SUCCESS(status))
{
// Try a different value type. Some vendors write the key as a multi-string type.
queryArgs.ValueType = REG_MULTI_SZ;
Status = D3DKMTQueryAdapterInfo(&queryAdapterInfo);
if (NT_SUCCESS(Status))
queryArgs.value_type = REG_MULTI_SZ;
status = pQueryAdapterInfo(&queryAdapterInfo);
if (NT_SUCCESS(status))
{
KHR_ICD_TRACE("Accepting multi-string registry key type\n");
}
Expand All @@ -132,42 +132,41 @@ bool khrIcdOsVendorsEnumerateDXGK(void)
continue;
}
}
if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW)
{
ULONG queryBufferSize = sizeof(D3DDDI_QUERYREGISTRY_INFO) + queryArgs.OutputValueSize;
pQueryBuffer = (D3DDDI_QUERYREGISTRY_INFO*)malloc(queryBufferSize);
ULONG queryBufferSize = sizeof(LoaderQueryRegistryInfo) + queryArgs.output_value_size;
pQueryBuffer = malloc(queryBufferSize);
if (pQueryBuffer == NULL)
continue;
memcpy(pQueryBuffer, &queryArgs, sizeof(D3DDDI_QUERYREGISTRY_INFO));
queryAdapterInfo.pPrivateDriverData = pQueryBuffer;
queryAdapterInfo.PrivateDriverDataSize = queryBufferSize;
Status = D3DKMTQueryAdapterInfo(&queryAdapterInfo);
memcpy(pQueryBuffer, &queryArgs, sizeof(LoaderQueryRegistryInfo));
queryAdapterInfo.private_data = pQueryBuffer;
queryAdapterInfo.private_data_size = queryBufferSize;
status = pQueryAdapterInfo(&queryAdapterInfo);
pQueryArgs = pQueryBuffer;
}
if (NT_SUCCESS(Status) && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_SUCCESS)
{
wchar_t* pWchar = pQueryArgs->OutputString;
wchar_t* pWchar = pQueryArgs->output_string;
memset(cszLibraryName, 0, sizeof(cszLibraryName));
{
size_t len = wcstombs(cszLibraryName, pWchar, sizeof(cszLibraryName));
size_t len;
wcstombs_s(&len, cszLibraryName, sizeof(cszLibraryName), pWchar, sizeof(cszLibraryName));
KHR_ICD_ASSERT(len == (sizeof(cszLibraryName) - 1));
ret |= adapterAdd(cszLibraryName, pAdapterInfo[AdapterIndex].AdapterLuid);
ret |= adapterAdd(cszLibraryName, EnumAdapters.adapters[AdapterIndex].luid);
}
}
else if (Status == STATUS_INVALID_PARAMETER && pQueryArgs->Status == D3DDDI_QUERYREGISTRY_STATUS_FAIL)
else if (status == STATUS_INVALID_PARAMETER)
{
free(pQueryBuffer);
goto out;
}
free(pQueryBuffer);
}
out:
free(pAdapterInfo);
free(EnumAdapters.adapters);
}

FreeLibrary(h);

#endif
#endif
return ret;
}

0 comments on commit fe09ad1

Please sign in to comment.