f89fa253b33dd177deb2fcc204f68b49305b8cf5
[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 /*
90  * 
91  * Vendor enumeration functions
92  *
93  */
94
95 // go through the list of vendors in the registry and call khrIcdVendorAdd 
96 // for each vendor encountered
97 BOOL CALLBACK khrIcdOsVendorsEnumerate(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContext)
98 {
99     LONG result;
100     BOOL status = FALSE;
101     const char* platformsName = "SOFTWARE\\Khronos\\OpenCL\\Vendors";
102     HKEY platformsKey = NULL;
103     DWORD dwIndex;
104
105     khrIcdVendorsEnumerateEnv();
106
107     if (!khrIcdOsVendorsEnumerateDXGK())
108     {
109         KHR_ICD_TRACE("Failed to load via DXGK interface on RS4, continuing\n");
110         if (!khrIcdOsVendorsEnumerateHKR())
111         {
112             KHR_ICD_TRACE("Failed to enumerate HKR entries, continuing\n");
113         }
114     }
115
116     KHR_ICD_TRACE("Opening key HKLM\\%s...\n", platformsName);
117     result = RegOpenKeyExA(
118         HKEY_LOCAL_MACHINE,
119         platformsName,
120         0,
121         KEY_READ,
122         &platformsKey);
123     if (ERROR_SUCCESS != result)
124     {
125         KHR_ICD_TRACE("Failed to open platforms key %s, continuing\n", platformsName);
126     }
127     else
128     {
129         // for each value
130         for (dwIndex = 0;; ++dwIndex)
131         {
132             char cszLibraryName[1024] = {0};
133             DWORD dwLibraryNameSize = sizeof(cszLibraryName);
134             DWORD dwLibraryNameType = 0;
135             DWORD dwValue = 0;
136             DWORD dwValueSize = sizeof(dwValue);
137
138             // read the value name
139             KHR_ICD_TRACE("Reading value %d...\n", dwIndex);
140             result = RegEnumValueA(
141                   platformsKey,
142                   dwIndex,
143                   cszLibraryName,
144                   &dwLibraryNameSize,
145                   NULL,
146                   &dwLibraryNameType,
147                   (LPBYTE)&dwValue,
148                   &dwValueSize);
149             // if RegEnumKeyEx fails, we are done with the enumeration
150             if (ERROR_SUCCESS != result)
151             {
152                 KHR_ICD_TRACE("Failed to read value %d, done reading key.\n", dwIndex);
153                 break;
154             }
155             KHR_ICD_TRACE("Value %s found...\n", cszLibraryName);
156         
157             // Require that the value be a DWORD and equal zero
158             if (REG_DWORD != dwLibraryNameType)
159             {
160                 KHR_ICD_TRACE("Value not a DWORD, skipping\n");
161                 continue;
162             }
163             if (dwValue)
164             {
165                 KHR_ICD_TRACE("Value not zero, skipping\n");
166                 continue;
167             }
168             // add the library
169             status |= adapterAdd(cszLibraryName, ZeroLuid);
170         }
171     }
172
173     // Add adapters according to DXGI's preference order
174     HMODULE hDXGI = LoadLibrary("dxgi.dll");
175     if (hDXGI)
176     {
177         IDXGIFactory* pFactory = NULL;
178         PFN_CREATE_DXGI_FACTORY pCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY)GetProcAddress(hDXGI, "CreateDXGIFactory");
179         HRESULT hr = pCreateDXGIFactory(&IID_IDXGIFactory, &pFactory);
180         if (SUCCEEDED(hr))
181         {
182             UINT i = 0;
183             IDXGIAdapter* pAdapter = NULL;
184             while (SUCCEEDED(pFactory->lpVtbl->EnumAdapters(pFactory, i++, &pAdapter)))
185             {
186                 DXGI_ADAPTER_DESC AdapterDesc;
187                 pAdapter->lpVtbl->GetDesc(pAdapter, &AdapterDesc);
188
189                 for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
190                 {
191                     if (iterAdapter->luid.LowPart == AdapterDesc.AdapterLuid.LowPart
192                         && iterAdapter->luid.HighPart == AdapterDesc.AdapterLuid.HighPart)
193                     {
194                         khrIcdVendorAdd(iterAdapter->szName);
195                         break;
196                     }
197                 }
198
199                 pAdapter->lpVtbl->Release(pAdapter);
200             }
201             pFactory->lpVtbl->Release(pFactory);
202         }
203         FreeLibrary(hDXGI);
204     }
205
206     // Go through the list again, putting any remaining adapters at the end of the list in an undefined order
207     for (WinAdapter* iterAdapter = pWinAdapterBegin; iterAdapter != pWinAdapterEnd; ++iterAdapter)
208     {
209         khrIcdVendorAdd(iterAdapter->szName);
210     }
211
212     free(pWinAdapterBegin);     
213
214     result = RegCloseKey(platformsKey);
215     if (ERROR_SUCCESS != result)
216     {
217         KHR_ICD_TRACE("Failed to close platforms key %s, ignoring\n", platformsName);
218     }
219     return status;
220 }
221
222 // go through the list of vendors only once
223 void khrIcdOsVendorsEnumerateOnce()
224 {
225     InitOnceExecuteOnce(&initialized, khrIcdOsVendorsEnumerate, NULL, NULL);
226 }
227  
228 /*
229  * 
230  * Dynamic library loading functions
231  *
232  */
233
234 // dynamically load a library.  returns NULL on failure
235 void *khrIcdOsLibraryLoad(const char *libraryName)
236 {
237     return (void *)LoadLibraryA(libraryName);
238 }
239
240 // get a function pointer from a loaded library.  returns NULL on failure.
241 void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
242 {
243     if (!library || !functionName)
244     {
245         return NULL;
246     }
247     return GetProcAddress( (HMODULE)library, functionName);
248 }
249
250 // unload a library.
251 void khrIcdOsLibraryUnload(void *library)
252 {
253     FreeLibrary( (HMODULE)library);
254 }