1 /*
2 * Copyright (c) 2016-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 <initguid.h>
20
21 #include "icd.h"
22 #include "icd_windows.h"
23 #include "icd_windows_hkr.h"
24 #include "icd_windows_dxgk.h"
25 #include "icd_windows_apppackage.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <windows.h>
29 #include <winreg.h>
30
31 #include <dxgi.h>
32 typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID, void **);
33
34 static INIT_ONCE initialized = INIT_ONCE_STATIC_INIT;
35
36 typedef struct WinAdapter
37 {
38 char * szName;
39 LUID luid;
40 } WinAdapter;
41
42 const LUID ZeroLuid = { 0, 0 };
43
44 static WinAdapter* pWinAdapterBegin = NULL;
45 static WinAdapter* pWinAdapterEnd = NULL;
46 static WinAdapter* pWinAdapterCapacity = NULL;
47
adapterAdd(const char * szName,LUID luid)48 BOOL adapterAdd(const char* szName, LUID luid)
49 {
50 BOOL result = TRUE;
51 if (pWinAdapterEnd == pWinAdapterCapacity)
52 {
53 size_t oldCapacity = pWinAdapterCapacity - pWinAdapterBegin;
54 size_t newCapacity = oldCapacity;
55 if (0 == newCapacity)
56 {
57 newCapacity = 1;
58 }
59 else if(newCapacity < UINT_MAX/2)
60 {
61 newCapacity *= 2;
62 }
63
64 WinAdapter* pNewBegin = malloc(newCapacity * sizeof(*pWinAdapterBegin));
65 if (!pNewBegin)
66 result = FALSE;
67 else
68 {
69 if (pWinAdapterBegin)
70 {
71 memcpy(pNewBegin, pWinAdapterBegin, oldCapacity * sizeof(*pWinAdapterBegin));
72 free(pWinAdapterBegin);
73 }
74 pWinAdapterCapacity = pNewBegin + newCapacity;
75 pWinAdapterEnd = pNewBegin + oldCapacity;
76 pWinAdapterBegin = pNewBegin;
77 }
78 }
79 if (pWinAdapterEnd != pWinAdapterCapacity)
80 {
81 size_t nameLen = (strlen(szName) + 1)*sizeof(szName[0]);
82 pWinAdapterEnd->szName = malloc(nameLen);
83 if (!pWinAdapterEnd->szName)
84 result = FALSE;
85 else
86 {
87 memcpy(pWinAdapterEnd->szName, szName, nameLen);
88 pWinAdapterEnd->luid = luid;
89 ++pWinAdapterEnd;
90 }
91 }
92 return result;
93 }
94
adapterFree(WinAdapter * pWinAdapter)95 void adapterFree(WinAdapter *pWinAdapter)
96 {
97 free(pWinAdapter->szName);
98 pWinAdapter->szName = NULL;
99 }
100
101 #if defined(CL_ENABLE_LAYERS)
102 typedef struct WinLayer
103 {
104 char * szName;
105 DWORD priority;
106 } WinLayer;
107
108 static WinLayer* pWinLayerBegin;
109 static WinLayer* pWinLayerEnd;
110 static WinLayer* pWinLayerCapacity;
111
compareLayer(const void * a,const void * b)112 static int compareLayer(const void *a, const void *b)
113 {
114 return ((WinLayer *)a)->priority < ((WinLayer *)b)->priority ? -1 :
115 ((WinLayer *)a)->priority > ((WinLayer *)b)->priority ? 1 : 0;
116 }
117
layerAdd(const char * szName,DWORD priority)118 static BOOL layerAdd(const char* szName, DWORD priority)
119 {
120 BOOL result = TRUE;
121 if (pWinLayerEnd == pWinLayerCapacity)
122 {
123 size_t oldCapacity = pWinLayerCapacity - pWinLayerBegin;
124 size_t newCapacity = oldCapacity;
125 if (0 == newCapacity)
126 {
127 newCapacity = 1;
128 }
129 else if(newCapacity < UINT_MAX/2)
130 {
131 newCapacity *= 2;
132 }
133
134 WinLayer* pNewBegin = malloc(newCapacity * sizeof(*pWinLayerBegin));
135 if (!pNewBegin)
136 {
137 KHR_ICD_TRACE("Failed allocate space for Layers array\n");
138 result = FALSE;
139 }
140 else
141 {
142 if (pWinLayerBegin)
143 {
144 memcpy(pNewBegin, pWinLayerBegin, oldCapacity * sizeof(*pWinLayerBegin));
145 free(pWinLayerBegin);
146 }
147 pWinLayerCapacity = pNewBegin + newCapacity;
148 pWinLayerEnd = pNewBegin + oldCapacity;
149 pWinLayerBegin = pNewBegin;
150 }
151 }
152 if (pWinLayerEnd != pWinLayerCapacity)
153 {
154 size_t nameLen = (strlen(szName) + 1)*sizeof(szName[0]);
155 pWinLayerEnd->szName = malloc(nameLen);
156 if (!pWinLayerEnd->szName)
157 {
158 KHR_ICD_TRACE("Failed allocate space for Layer file path\n");
159 result = FALSE;
160 }
161 else
162 {
163 memcpy(pWinLayerEnd->szName, szName, nameLen);
164 pWinLayerEnd->priority = priority;
165 ++pWinLayerEnd;
166 }
167 }
168 return result;
169 }
170
layerFree(WinLayer * pWinLayer)171 void layerFree(WinLayer *pWinLayer)
172 {
173 free(pWinLayer->szName);
174 pWinLayer->szName = NULL;
175 }
176 #endif // defined(CL_ENABLE_LAYERS)
177
178 /*
179 *
180 * Vendor enumeration functions
181 *
182 */
183
184 // go through the list of vendors in the registry and call khrIcdVendorAdd
185 // for each vendor encountered
khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * lpContext)186 BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
187 {
188 LONG result;
189 BOOL status = FALSE, currentStatus = FALSE;
190 const char* platformsName = "SOFTWARE\\Khronos\\OpenCL\\Vendors";
191 HKEY platformsKey = NULL;
192 DWORD dwIndex;
193
194 khrIcdInitializeTrace();
195 khrIcdVendorsEnumerateEnv();
196
197 currentStatus = khrIcdOsVendorsEnumerateDXGK();
198 status |= currentStatus;
199 if (!currentStatus)
200 {
201 KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
202 }
203
204 currentStatus = khrIcdOsVendorsEnumerateHKR();
205 status |= currentStatus;
206 if (!currentStatus)
207 {
208 KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
209 }
210
211 currentStatus = khrIcdOsVendorsEnumerateAppPackage();
212 status |= currentStatus;
213 if (!currentStatus)
214 {
215 KHR_ICD_TRACE("Failed to enumerate App package entry, continuing\n");
216 }
217
218 KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName);
219 result = RegOpenKeyExA(
220 HKEY_LOCAL_MACHINE,
221 platformsName,
222 0,
223 KEY_READ,
224 &platformsKey);
225 if (ERROR_SUCCESS != result)
226 {
227 KHR_ICD_TRACE("Failed to open platforms key %s, continuing\n", platformsName);
228 }
229 else
230 {
231 // for each value
232 for (dwIndex = 0;; ++dwIndex)
233 {
234 char cszLibraryName[1024] = {0};
235 DWORD dwLibraryNameSize = sizeof(cszLibraryName);
236 DWORD dwLibraryNameType = 0;
237 DWORD dwValue = 0;
238 DWORD dwValueSize = sizeof(dwValue);
239
240 // read the value name
241 KHR_ICD_TRACE("Reading value %"PRIuDW"...\n", dwIndex);
242 result = RegEnumValueA(
243 platformsKey,
244 dwIndex,
245 cszLibraryName,
246 &dwLibraryNameSize,
247 NULL,
248 &dwLibraryNameType,
249 (LPBYTE)&dwValue,
250 &dwValueSize);
251 // if RegEnumKeyEx fails, we are done with the enumeration
252 if (ERROR_SUCCESS != result)
253 {
254 KHR_ICD_TRACE("Failed to read value %"PRIuDW", done reading key.\n", dwIndex);
255 break;
256 }
257 KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
258
259 // Require that the value be a DWORD and equal zero
260 if (REG_DWORD != dwLibraryNameType)
261 {
262 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
263 continue;
264 }
265 if (dwValue)
266 {
267 KHR_ICD_TRACE("Value not zero, skipping\n");
268 continue;
269 }
270 // add the library
271 status |= adapterAdd(cszLibraryName, ZeroLuid);
272 }
273 }
274
275 // Add adapters according to DXGI's preference order
276 HMODULE hDXGI = LoadLibraryA("dxgi.dll");
277 if (hDXGI)
278 {
279 IDXGIFactory* pFactory = NULL;
280 PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
281 if (pCreateDXGIFactory)
282 {
283 HRESULT hr = pCreateDXGIFactory(&IID_IDXGIFactory, (void **)&pFactory);
284 if (SUCCEEDED(hr))
285 {
286 UINT i = 0;
287 IDXGIAdapter* pAdapter = NULL;
288 while (SUCCEEDED(pFactory->lpVtbl->EnumAdapters(pFactory, i++, &pAdapter)))
289 {
290 DXGI_ADAPTER_DESC AdapterDesc;
291 if (SUCCEEDED(pAdapter->lpVtbl->GetDesc(pAdapter, &AdapterDesc)))
292 {
293 for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
294 {
295 if (iterAdapter->luid.LowPart == AdapterDesc.AdapterLuid.LowPart
296 && iterAdapter->luid.HighPart == AdapterDesc.AdapterLuid.HighPart)
297 {
298 khrIcdVendorAdd(iterAdapter->szName);
299 break;
300 }
301 }
302 }
303
304 pAdapter->lpVtbl->Release(pAdapter);
305 }
306 pFactory->lpVtbl->Release(pFactory);
307 }
308 }
309 FreeLibrary(hDXGI);
310 }
311
312 // Go through the list again, putting any remaining adapters at the end of the list in an undefined order
313 for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
314 {
315 khrIcdVendorAdd(iterAdapter->szName);
316 adapterFree(iterAdapter);
317 }
318
319 free(pWinAdapterBegin);
320 pWinAdapterBegin = NULL;
321 pWinAdapterEnd = NULL;
322 pWinAdapterCapacity = NULL;
323
324 result = RegCloseKey(platformsKey);
325 if (ERROR_SUCCESS != result)
326 {
327 KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
328 }
329
330 #if defined(CL_ENABLE_LAYERS)
331 const char* layersName = "SOFTWARE\\Khronos\\OpenCL\\Layers";
332 HKEY layersKey = NULL;
333
334 KHR_ICD_TRACE("Opening key HKLM\\%s...\n", layersName);
335 result = RegOpenKeyExA(
336 HKEY_LOCAL_MACHINE,
337 layersName,
338 0,
339 KEY_READ,
340 &layersKey);
341 if (ERROR_SUCCESS != result)
342 {
343 KHR_ICD_TRACE("Failed to open layers key %s, continuing\n", layersName);
344 }
345 else
346 {
347 // for each value
348 for (dwIndex = 0;; ++dwIndex)
349 {
350 char cszLibraryName[1024] = {0};
351 DWORD dwLibraryNameSize = sizeof(cszLibraryName);
352 DWORD dwLibraryNameType = 0;
353 DWORD dwValue = 0;
354 DWORD dwValueSize = sizeof(dwValue);
355
356 // read the value name
357 KHR_ICD_TRACE("Reading value %"PRIuDW"...\n", dwIndex);
358 result = RegEnumValueA(
359 layersKey,
360 dwIndex,
361 cszLibraryName,
362 &dwLibraryNameSize,
363 NULL,
364 &dwLibraryNameType,
365 (LPBYTE)&dwValue,
366 &dwValueSize);
367 // if RegEnumKeyEx fails, we are done with the enumeration
368 if (ERROR_SUCCESS != result)
369 {
370 KHR_ICD_TRACE("Failed to read value %"PRIuDW", done reading key.\n", dwIndex);
371 break;
372 }
373 KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
374
375 // Require that the value be a DWORD
376 if (REG_DWORD != dwLibraryNameType)
377 {
378 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
379 continue;
380 }
381 // add the library
382 status |= layerAdd(cszLibraryName, dwValue);
383 }
384 qsort(pWinLayerBegin, pWinLayerEnd - pWinLayerBegin, sizeof(WinLayer), compareLayer);
385 for (WinLayer* iterLayer = pWinLayerBegin; iterLayer != pWinLayerEnd; ++iterLayer)
386 {
387 khrIcdLayerAdd(iterLayer->szName);
388 layerFree(iterLayer);
389 }
390 }
391
392 free(pWinLayerBegin);
393 pWinLayerBegin = NULL;
394 pWinLayerEnd = NULL;
395 pWinLayerCapacity = NULL;
396
397 result = RegCloseKey(layersKey);
398
399 khrIcdLayersEnumerateEnv();
400 #endif // defined(CL_ENABLE_LAYERS)
401 return status;
402 }
403
404 // go through the list of vendors only once
khrIcdOsVendorsEnumerateOnce()405 void khrIcdOsVendorsEnumerateOnce()
406 {
407 InitOnceExecuteOnce(&initialized, khrIcdOsVendorsEnumerate, NULL, NULL);
408 }
409
410 /*
411 *
412 * Dynamic library loading functions
413 *
414 */
415
416 // dynamically load a library. returns NULL on failure
khrIcdOsLibraryLoad(const char * libraryName)417 void *khrIcdOsLibraryLoad(const char *libraryName)
418 {
419 HMODULE hTemp = LoadLibraryExA(libraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
420 if (!hTemp && GetLastError() == ERROR_INVALID_PARAMETER)
421 {
422 hTemp = LoadLibraryExA(libraryName, NULL, 0);
423 }
424 if (!hTemp)
425 {
426 KHR_ICD_TRACE("Failed to load driver. Windows error code is %"PRIuDW".\n", GetLastError());
427 }
428 return (void*)hTemp;
429 }
430
431 // get a function pointer from a loaded library. returns NULL on failure.
khrIcdOsLibraryGetFunctionAddress(void * library,const char * functionName)432 void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
433 {
434 if (!library || !functionName)
435 {
436 return NULL;
437 }
438 return GetProcAddress( (HMODULE)library, functionName);
439 }
440
441 // unload a library.
khrIcdOsLibraryUnload(void * library)442 void khrIcdOsLibraryUnload(void *library)
443 {
444 FreeLibrary( (HMODULE)library);
445 }
446