1 /*
2 * Copyright (c) 2017-2020 The Khronos Group Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * OpenCL is a trademark of Apple Inc. used under license by Khronos.
17 */
18
19 #include "icd.h"
20 #include "icd_windows_dxgk.h"
21
22 #include <windows.h>
23 #include "adapter.h"
24
25 #ifndef NTSTATUS
26 typedef LONG NTSTATUS;
27 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
28 #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
29 #define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
30 #endif
31
khrIcdOsVendorsEnumerateDXGK(void)32 bool khrIcdOsVendorsEnumerateDXGK(void)
33 {
34 bool ret = false;
35 int result = 0;
36
37 // Get handle to GDI Runtime
38 HMODULE h = LoadLibraryA("gdi32.dll");
39 if (h == NULL)
40 return ret;
41
42 if(GetProcAddress(h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
43 {
44 LoaderEnumAdapters2 EnumAdapters;
45 NTSTATUS status = STATUS_SUCCESS;
46
47 EnumAdapters.adapter_count = 0;
48 EnumAdapters.adapters = NULL;
49 PFN_LoaderEnumAdapters2 pEnumAdapters2 = (PFN_LoaderEnumAdapters2)GetProcAddress(h, "D3DKMTEnumAdapters2");
50 if (!pEnumAdapters2)
51 {
52 KHR_ICD_TRACE("GetProcAddress failed for D3DKMTEnumAdapters2\n");
53 goto out;
54 }
55 PFN_LoaderQueryAdapterInfo pQueryAdapterInfo = (PFN_LoaderQueryAdapterInfo)GetProcAddress(h, "D3DKMTQueryAdapterInfo");
56 if (!pQueryAdapterInfo)
57 {
58 KHR_ICD_TRACE("GetProcAddress failed for D3DKMTQueryAdapterInfo\n");
59 goto out;
60 }
61 while (1)
62 {
63 EnumAdapters.adapter_count = 0;
64 EnumAdapters.adapters = NULL;
65 status = pEnumAdapters2(&EnumAdapters);
66 if (status == STATUS_BUFFER_TOO_SMALL)
67 {
68 // Number of Adapters increased between calls, retry;
69 continue;
70 }
71 else if (!NT_SUCCESS(status))
72 {
73 KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
74 goto out;
75 }
76 break;
77 }
78 EnumAdapters.adapters = malloc(sizeof(*EnumAdapters.adapters)*(EnumAdapters.adapter_count));
79 if (EnumAdapters.adapters == NULL)
80 {
81 KHR_ICD_TRACE("Allocation failure for adapters buffer\n");
82 goto out;
83 }
84 status = pEnumAdapters2(&EnumAdapters);
85 if (!NT_SUCCESS(status))
86 {
87 KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
88 goto out;
89 }
90 const char* cszOpenCLRegKeyName = getOpenCLRegKeyName();
91 const int szOpenCLRegKeyName = (int)(strlen(cszOpenCLRegKeyName) + 1)*sizeof(cszOpenCLRegKeyName[0]);
92 for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.adapter_count; AdapterIndex++)
93 {
94 LoaderQueryRegistryInfo queryArgs = {0};
95 LoaderQueryRegistryInfo* pQueryArgs = &queryArgs;
96 LoaderQueryRegistryInfo* pQueryBuffer = NULL;
97 queryArgs.query_type = LOADER_QUERY_REGISTRY_ADAPTER_KEY;
98 queryArgs.query_flags.translate_path = TRUE;
99 queryArgs.value_type = REG_SZ;
100 result = MultiByteToWideChar(
101 CP_UTF8,
102 0,
103 cszOpenCLRegKeyName,
104 szOpenCLRegKeyName,
105 queryArgs.value_name,
106 ARRAYSIZE(queryArgs.value_name));
107 if (!result)
108 {
109 KHR_ICD_TRACE("MultiByteToWideChar status != SUCCESS\n");
110 continue;
111 }
112 LoaderQueryAdapterInfo queryAdapterInfo = {0};
113 queryAdapterInfo.handle = EnumAdapters.adapters[AdapterIndex].handle;
114 queryAdapterInfo.type = LOADER_QUERY_TYPE_REGISTRY;
115 queryAdapterInfo.private_data = &queryArgs;
116 queryAdapterInfo.private_data_size = sizeof(queryArgs);
117 status = pQueryAdapterInfo(&queryAdapterInfo);
118 if (!NT_SUCCESS(status))
119 {
120 // Try a different value type. Some vendors write the key as a multi-string type.
121 queryArgs.value_type = REG_MULTI_SZ;
122 status = pQueryAdapterInfo(&queryAdapterInfo);
123 if (NT_SUCCESS(status))
124 {
125 KHR_ICD_TRACE("Accepting multi-string registry key type\n");
126 }
127 else
128 {
129 // Continue trying to get as much info on each adapter as possible.
130 // It's too late to return FALSE and claim WDDM2_4 enumeration is not available here.
131 continue;
132 }
133 }
134 if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW)
135 {
136 ULONG queryBufferSize = sizeof(LoaderQueryRegistryInfo) + queryArgs.output_value_size;
137 pQueryBuffer = malloc(queryBufferSize);
138 if (pQueryBuffer == NULL)
139 continue;
140 memcpy(pQueryBuffer, &queryArgs, sizeof(LoaderQueryRegistryInfo));
141 queryAdapterInfo.private_data = pQueryBuffer;
142 queryAdapterInfo.private_data_size = queryBufferSize;
143 status = pQueryAdapterInfo(&queryAdapterInfo);
144 pQueryArgs = pQueryBuffer;
145 }
146 if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_SUCCESS)
147 {
148 char cszLibraryName[MAX_PATH];
149 result = WideCharToMultiByte(
150 CP_UTF8,
151 0,
152 pQueryArgs->output_string,
153 -1,
154 cszLibraryName,
155 MAX_PATH,
156 NULL,
157 NULL);
158 if (!result)
159 {
160 KHR_ICD_TRACE("WideCharToMultiByte status != SUCCESS\n");
161 }
162 else
163 {
164 ret |= adapterAdd(cszLibraryName, EnumAdapters.adapters[AdapterIndex].luid);
165 }
166 }
167 else if (status == (NTSTATUS)STATUS_INVALID_PARAMETER)
168 {
169 free(pQueryBuffer);
170 goto out;
171 }
172 free(pQueryBuffer);
173 }
174 out:
175 free(EnumAdapters.adapters);
176 }
177
178 FreeLibrary(h);
179
180 return ret;
181 }
182