• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 __cdecl 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     (void)InitOnce;
189     (void)Parameter;
190     (void)lpContext;
191 
192     LONG result;
193     BOOL status = FALSE, currentStatus = FALSE;
194     const char* platformsName = "SOFTWARE\\Khronos\\OpenCL\\Vendors";
195     HKEY platformsKey = NULL;
196     DWORD dwIndex;
197 
198     khrIcdInitializeTrace();
199     khrIcdVendorsEnumerateEnv();
200 
201     currentStatus = khrIcdOsVendorsEnumerateDXGK();
202     status |= currentStatus;
203     if (!currentStatus)
204     {
205         KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
206     }
207 
208     currentStatus = khrIcdOsVendorsEnumerateHKR();
209     status |= currentStatus;
210     if (!currentStatus)
211     {
212         KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
213     }
214 
215     currentStatus = khrIcdOsVendorsEnumerateAppPackage();
216     status |= currentStatus;
217     if (!currentStatus)
218     {
219         KHR_ICD_TRACE("Failed to enumerate App package entry, continuing\n");
220     }
221 
222     KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName);
223     result = RegOpenKeyExA(
224         HKEY_LOCAL_MACHINE,
225         platformsName,
226         0,
227         KEY_READ,
228         &platformsKey);
229     if (ERROR_SUCCESS != result)
230     {
231         KHR_ICD_TRACE("Failed to open platforms key %s, continuing\n", platformsName);
232     }
233     else
234     {
235         // for each value
236         for (dwIndex = 0;; ++dwIndex)
237         {
238             char cszLibraryName[1024] = {0};
239             DWORD dwLibraryNameSize = sizeof(cszLibraryName);
240             DWORD dwLibraryNameType = 0;
241             DWORD dwValue = 0;
242             DWORD dwValueSize = sizeof(dwValue);
243 
244             // read the value name
245             KHR_ICD_TRACE("Reading value %"PRIuDW"...\n", dwIndex);
246             result = RegEnumValueA(
247                   platformsKey,
248                   dwIndex,
249                   cszLibraryName,
250                   &dwLibraryNameSize,
251                   NULL,
252                   &dwLibraryNameType,
253                   (LPBYTE)&dwValue,
254                   &dwValueSize);
255             // if RegEnumKeyEx fails, we are done with the enumeration
256             if (ERROR_SUCCESS != result)
257             {
258                 KHR_ICD_TRACE("Failed to read value %"PRIuDW", done reading key.\n", dwIndex);
259                 break;
260             }
261             KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
262 
263             // Require that the value be a DWORD and equal zero
264             if (REG_DWORD != dwLibraryNameType)
265             {
266                 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
267                 continue;
268             }
269             if (dwValue)
270             {
271                 KHR_ICD_TRACE("Value not zero, skipping\n");
272                 continue;
273             }
274             // add the library
275             status |= adapterAdd(cszLibraryName, ZeroLuid);
276         }
277     }
278 
279     // Add adapters according to DXGI's preference order
280     HMODULE hDXGI = LoadLibraryA("dxgi.dll");
281     if (hDXGI)
282     {
283         IDXGIFactory* pFactory = NULL;
284         PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
285         if (pCreateDXGIFactory)
286         {
287             HRESULT hr = pCreateDXGIFactory(&IID_IDXGIFactory, (void **)&pFactory);
288             if (SUCCEEDED(hr))
289             {
290                 UINT i = 0;
291                 IDXGIAdapter* pAdapter = NULL;
292                 while (SUCCEEDED(pFactory->lpVtbl->EnumAdapters(pFactory, i++, &pAdapter)))
293                 {
294                     DXGI_ADAPTER_DESC AdapterDesc;
295                     if (SUCCEEDED(pAdapter->lpVtbl->GetDesc(pAdapter, &AdapterDesc)))
296                     {
297                         for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
298                         {
299                             if (iterAdapter->luid.LowPart == AdapterDesc.AdapterLuid.LowPart
300                                 && iterAdapter->luid.HighPart == AdapterDesc.AdapterLuid.HighPart)
301                             {
302                                 khrIcdVendorAdd(iterAdapter->szName);
303                                 break;
304                             }
305                         }
306                     }
307 
308                     pAdapter->lpVtbl->Release(pAdapter);
309                 }
310                 pFactory->lpVtbl->Release(pFactory);
311             }
312         }
313         FreeLibrary(hDXGI);
314     }
315 
316     // Go through the list again, putting any remaining adapters at the end of the list in an undefined order
317     for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
318     {
319         khrIcdVendorAdd(iterAdapter->szName);
320         adapterFree(iterAdapter);
321     }
322 
323     free(pWinAdapterBegin);
324     pWinAdapterBegin = NULL;
325     pWinAdapterEnd = NULL;
326     pWinAdapterCapacity = NULL;
327 
328     result = RegCloseKey(platformsKey);
329     if (ERROR_SUCCESS != result)
330     {
331         KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
332     }
333 
334 #if defined(CL_ENABLE_LAYERS)
335     const char* layersName = "SOFTWARE\\Khronos\\OpenCL\\Layers";
336     HKEY layersKey = NULL;
337 
338     KHR_ICD_TRACE("Opening key HKLM\\%s...\n", layersName);
339     result = RegOpenKeyExA(
340         HKEY_LOCAL_MACHINE,
341         layersName,
342         0,
343         KEY_READ,
344         &layersKey);
345     if (ERROR_SUCCESS != result)
346     {
347         KHR_ICD_TRACE("Failed to open layers key %s, continuing\n", layersName);
348     }
349     else
350     {
351         // for each value
352         for (dwIndex = 0;; ++dwIndex)
353         {
354             char cszLibraryName[1024] = {0};
355             DWORD dwLibraryNameSize = sizeof(cszLibraryName);
356             DWORD dwLibraryNameType = 0;
357             DWORD dwValue = 0;
358             DWORD dwValueSize = sizeof(dwValue);
359 
360             // read the value name
361             KHR_ICD_TRACE("Reading value %"PRIuDW"...\n", dwIndex);
362             result = RegEnumValueA(
363                   layersKey,
364                   dwIndex,
365                   cszLibraryName,
366                   &dwLibraryNameSize,
367                   NULL,
368                   &dwLibraryNameType,
369                   (LPBYTE)&dwValue,
370                   &dwValueSize);
371             // if RegEnumKeyEx fails, we are done with the enumeration
372             if (ERROR_SUCCESS != result)
373             {
374                 KHR_ICD_TRACE("Failed to read value %"PRIuDW", done reading key.\n", dwIndex);
375                 break;
376             }
377             KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
378 
379             // Require that the value be a DWORD
380             if (REG_DWORD != dwLibraryNameType)
381             {
382                 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
383                 continue;
384             }
385             // add the library
386             status |= layerAdd(cszLibraryName, dwValue);
387         }
388         qsort(pWinLayerBegin, pWinLayerEnd - pWinLayerBegin, sizeof(WinLayer), compareLayer);
389         for (WinLayer* iterLayer = pWinLayerBegin; iterLayer != pWinLayerEnd; ++iterLayer)
390         {
391             khrIcdLayerAdd(iterLayer->szName);
392             layerFree(iterLayer);
393         }
394     }
395 
396     free(pWinLayerBegin);
397     pWinLayerBegin = NULL;
398     pWinLayerEnd = NULL;
399     pWinLayerCapacity = NULL;
400 
401     result = RegCloseKey(layersKey);
402 
403     khrIcdLayersEnumerateEnv();
404 #endif // defined(CL_ENABLE_LAYERS)
405     return status;
406 }
407 
408 // go through the list of vendors only once
khrIcdOsVendorsEnumerateOnce()409 void khrIcdOsVendorsEnumerateOnce()
410 {
411     InitOnceExecuteOnce(&initialized, khrIcdOsVendorsEnumerate, NULL, NULL);
412 }
413 
414 /*
415  *
416  * Dynamic library loading functions
417  *
418  */
419 
420 // dynamically load a library.  returns NULL on failure
khrIcdOsLibraryLoad(const char * libraryName)421 void *khrIcdOsLibraryLoad(const char *libraryName)
422 {
423     HMODULE hTemp = LoadLibraryExA(libraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
424     if (!hTemp && GetLastError() == ERROR_INVALID_PARAMETER)
425     {
426         hTemp = LoadLibraryExA(libraryName, NULL, 0);
427     }
428     if (!hTemp)
429     {
430         KHR_ICD_TRACE("Failed to load driver. Windows error code is %"PRIuDW".\n", GetLastError());
431     }
432     return (void*)hTemp;
433 }
434 
435 // get a function pointer from a loaded library.  returns NULL on failure.
khrIcdOsLibraryGetFunctionAddress(void * library,const char * functionName)436 void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
437 {
438     if (!library || !functionName)
439     {
440         return NULL;
441     }
442     return GetProcAddress( (HMODULE)library, functionName);
443 }
444 
445 // unload a library.
khrIcdOsLibraryUnload(void * library)446 void khrIcdOsLibraryUnload(void *library)
447 {
448     FreeLibrary( (HMODULE)library);
449 }
450