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