Minor fixes to Windows build to improve header include order resiliency (#126)
[platform/upstream/OpenCL-ICD-Loader.git] / loader / windows / icd_windows.c
1 /*
2  * Copyright (c) 2016-2019 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 <windows.h>
28 #include <winreg.h>
29
30 #include <dxgi.h>
31 typedef HRESULT (WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID, void **);
32
33 static INIT_ONCE initialized = INIT_ONCE_STATIC_INIT;
34
35 typedef struct WinAdapter
36 {
37     char * szName;
38     LUID luid;
39 } WinAdapter;
40
41 const LUID ZeroLuid = { 0, 0 };
42
43 static WinAdapter* pWinAdapterBegin = NULL;
44 static WinAdapter* pWinAdapterEnd = NULL;
45 static WinAdapter* pWinAdapterCapacity = NULL;
46
47 BOOL adapterAdd(const char* szName, LUID luid)
48 {
49     BOOL result = TRUE;
50     if (pWinAdapterEnd == pWinAdapterCapacity)
51     {
52         size_t oldCapacity = pWinAdapterCapacity - pWinAdapterBegin;
53         size_t newCapacity = oldCapacity;
54         if (0 == newCapacity)
55         {
56             newCapacity = 1;
57         }
58         else if(newCapacity < UINT_MAX/2)
59         {
60             newCapacity *= 2;
61         }
62
63         WinAdapter* pNewBegin = malloc(newCapacity * sizeof(*pWinAdapterBegin));
64         if (!pNewBegin)
65             result = FALSE;
66         else
67         {
68             if (pWinAdapterBegin)
69             {
70                 memcpy(pNewBegin, pWinAdapterBegin, oldCapacity * sizeof(*pWinAdapterBegin));
71                 free(pWinAdapterBegin);
72             }
73             pWinAdapterCapacity = pNewBegin + newCapacity;
74             pWinAdapterEnd = pNewBegin + oldCapacity;
75             pWinAdapterBegin = pNewBegin;
76         }
77     }
78     if (pWinAdapterEnd != pWinAdapterCapacity)
79     {
80         size_t nameLen = (strlen(szName) + 1)*sizeof(szName[0]);
81         pWinAdapterEnd->szName = malloc(nameLen);
82         if (!pWinAdapterEnd->szName)
83             result = FALSE;
84         else
85         {
86             memcpy(pWinAdapterEnd->szName, szName, nameLen);
87             pWinAdapterEnd->luid = luid;
88             ++pWinAdapterEnd;
89         }
90     }
91     return result;
92 }
93
94 void adapterFree(WinAdapter *pWinAdapter)
95 {
96     free(pWinAdapter->szName);
97     pWinAdapter->szName = NULL;
98 }
99
100 /*
101  * 
102  * Vendor enumeration functions
103  *
104  */
105
106 // go through the list of vendors in the registry and call khrIcdVendorAdd 
107 // for each vendor encountered
108 BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
109 {
110     LONG result;
111     BOOL status = FALSE;
112     const char* platformsName = "SOFTWARE\\Khronos\\OpenCL\\Vendors";
113     HKEY platformsKey = NULL;
114     DWORD dwIndex;
115
116     khrIcdVendorsEnumerateEnv();
117
118     status |= khrIcdOsVendorsEnumerateDXGK();
119     if (!status)
120     {
121         KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
122         status |= khrIcdOsVendorsEnumerateHKR();
123         if (!status)
124         {
125             KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
126         }
127     }
128     
129     status |= khrIcdOsVendorsEnumerateAppPackage();
130
131     KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName);
132     result = RegOpenKeyExA(
133         HKEY_LOCAL_MACHINE,
134         platformsName,
135         0,
136         KEY_READ,
137         &platformsKey);
138     if (ERROR_SUCCESS != result)
139     {
140         KHR_ICD_TRACE("Failed to open platforms key %s, continuing\n", platformsName);
141     }
142     else
143     {
144         // for each value
145         for (dwIndex = 0;; ++dwIndex)
146         {
147             char cszLibraryName[1024] = {0};
148             DWORD dwLibraryNameSize = sizeof(cszLibraryName);
149             DWORD dwLibraryNameType = 0;
150             DWORD dwValue = 0;
151             DWORD dwValueSize = sizeof(dwValue);
152
153             // read the value name
154             KHR_ICD_TRACE("Reading value %d...\n", dwIndex);
155             result = RegEnumValueA(
156                   platformsKey,
157                   dwIndex,
158                   cszLibraryName,
159                   &dwLibraryNameSize,
160                   NULL,
161                   &dwLibraryNameType,
162                   (LPBYTE)&dwValue,
163                   &dwValueSize);
164             // if RegEnumKeyEx fails, we are done with the enumeration
165             if (ERROR_SUCCESS != result)
166             {
167                 KHR_ICD_TRACE("Failed to read value %d, done reading key.\n", dwIndex);
168                 break;
169             }
170             KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
171         
172             // Require that the value be a DWORD and equal zero
173             if (REG_DWORD != dwLibraryNameType)
174             {
175                 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
176                 continue;
177             }
178             if (dwValue)
179             {
180                 KHR_ICD_TRACE("Value not zero, skipping\n");
181                 continue;
182             }
183             // add the library
184             status |= adapterAdd(cszLibraryName, ZeroLuid);
185         }
186     }
187
188     // Add adapters according to DXGI's preference order
189     HMODULE hDXGI = LoadLibrary("dxgi.dll");
190     if (hDXGI)
191     {
192         IDXGIFactory* pFactory = NULL;
193         PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
194         if (pCreateDXGIFactory)
195         {
196             HRESULT hr = pCreateDXGIFactory(&IID_IDXGIFactory, &pFactory);
197             if (SUCCEEDED(hr))
198             {
199                 UINT i = 0;
200                 IDXGIAdapter* pAdapter = NULL;
201                 while (SUCCEEDED(pFactory->lpVtbl->EnumAdapters(pFactory, i++, &pAdapter)))
202                 {
203                     DXGI_ADAPTER_DESC AdapterDesc;
204                     if (SUCCEEDED(pAdapter->lpVtbl->GetDesc(pAdapter, &AdapterDesc)))
205                     {
206                         for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
207                         {
208                             if (iterAdapter->luid.LowPart == AdapterDesc.AdapterLuid.LowPart
209                                 && iterAdapter->luid.HighPart == AdapterDesc.AdapterLuid.HighPart)
210                             {
211                                 khrIcdVendorAdd(iterAdapter->szName);
212                                 break;
213                             }
214                         }
215                     }
216
217                     pAdapter->lpVtbl->Release(pAdapter);
218                 }
219                 pFactory->lpVtbl->Release(pFactory);
220             }
221             FreeLibrary(hDXGI);
222         }
223     }
224
225     // Go through the list again, putting any remaining adapters at the end of the list in an undefined order
226     for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
227     {
228         khrIcdVendorAdd(iterAdapter->szName);
229         adapterFree(iterAdapter);
230     }
231
232     free(pWinAdapterBegin);
233     pWinAdapterBegin = NULL;
234     pWinAdapterEnd = NULL;
235     pWinAdapterCapacity = NULL;
236
237     result = RegCloseKey(platformsKey);
238     if (ERROR_SUCCESS != result)
239     {
240         KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
241     }
242     return status;
243 }
244
245 // go through the list of vendors only once
246 void khrIcdOsVendorsEnumerateOnce()
247 {
248     InitOnceExecuteOnce(&initialized, khrIcdOsVendorsEnumerate, NULL, NULL);
249 }
250  
251 /*
252  * 
253  * Dynamic library loading functions
254  *
255  */
256
257 // dynamically load a library.  returns NULL on failure
258 void *khrIcdOsLibraryLoad(const char *libraryName)
259 {
260     HMODULE hTemp = LoadLibraryExA(libraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
261     if (!hTemp && GetLastError() == ERROR_INVALID_PARAMETER)
262     {
263         hTemp = LoadLibraryExA(libraryName, NULL, 0);
264     }
265     return (void*)hTemp;
266 }
267
268 // get a function pointer from a loaded library.  returns NULL on failure.
269 void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
270 {
271     if (!library || !functionName)
272     {
273         return NULL;
274     }
275     return GetProcAddress( (HMODULE)library, functionName);
276 }
277
278 // unload a library.
279 void khrIcdOsLibraryUnload(void *library)
280 {
281     FreeLibrary( (HMODULE)library);
282 }