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 "icd.h"
20 #include "icd_dispatch.h"
21 #include "icd_envvars.h"
22 #if defined(CL_ENABLE_LAYERS)
23 #include <CL/cl_layer.h>
24 #endif // defined(CL_ENABLE_LAYERS)
25 #include <stdlib.h>
26 #include <string.h>
27
28 KHRicdVendor *khrIcdVendors = NULL;
29 int khrEnableTrace = 0;
30
31 #if defined(CL_ENABLE_LAYERS)
32 struct KHRLayer *khrFirstLayer = NULL;
33 #endif // defined(CL_ENABLE_LAYERS)
34
35 // entrypoint to check and initialize trace.
khrIcdInitializeTrace(void)36 void khrIcdInitializeTrace(void)
37 {
38 char *enableTrace = khrIcd_getenv("OCL_ICD_ENABLE_TRACE");
39 if (enableTrace && (strcmp(enableTrace, "True") == 0 ||
40 strcmp(enableTrace, "true") == 0 ||
41 strcmp(enableTrace, "T") == 0 ||
42 strcmp(enableTrace, "1") == 0))
43 {
44 khrEnableTrace = 1;
45 }
46 }
47
48 // entrypoint to initialize the ICD and add all vendors
khrIcdInitialize(void)49 void khrIcdInitialize(void)
50 {
51 // enumerate vendors present on the system
52 khrIcdOsVendorsEnumerateOnce();
53 }
54
khrIcdVendorAdd(const char * libraryName)55 void khrIcdVendorAdd(const char *libraryName)
56 {
57 void *library = NULL;
58 cl_int result = CL_SUCCESS;
59 pfn_clGetExtensionFunctionAddress p_clGetExtensionFunctionAddress = NULL;
60 pfn_clIcdGetPlatformIDs p_clIcdGetPlatformIDs = NULL;
61 cl_uint i = 0;
62 cl_uint platformCount = 0;
63 cl_platform_id *platforms = NULL;
64 KHRicdVendor *vendorIterator = NULL;
65
66 // require that the library name be valid
67 if (!libraryName)
68 {
69 goto Done;
70 }
71 KHR_ICD_TRACE("attempting to add vendor %s...\n", libraryName);
72
73 // load its library and query its function pointers
74 library = khrIcdOsLibraryLoad(libraryName);
75 if (!library)
76 {
77 KHR_ICD_TRACE("failed to load library %s\n", libraryName);
78 goto Done;
79 }
80
81 // ensure that we haven't already loaded this vendor
82 for (vendorIterator = khrIcdVendors; vendorIterator; vendorIterator = vendorIterator->next)
83 {
84 if (vendorIterator->library == library)
85 {
86 KHR_ICD_TRACE("already loaded vendor %s, nothing to do here\n", libraryName);
87 goto Done;
88 }
89 }
90
91 // get the library's clGetExtensionFunctionAddress pointer
92 p_clGetExtensionFunctionAddress = (pfn_clGetExtensionFunctionAddress)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clGetExtensionFunctionAddress");
93 if (!p_clGetExtensionFunctionAddress)
94 {
95 KHR_ICD_TRACE("failed to get function address clGetExtensionFunctionAddress\n");
96 goto Done;
97 }
98
99 // use that function to get the clIcdGetPlatformIDsKHR function pointer
100 p_clIcdGetPlatformIDs = (pfn_clIcdGetPlatformIDs)(size_t)p_clGetExtensionFunctionAddress("clIcdGetPlatformIDsKHR");
101 if (!p_clIcdGetPlatformIDs)
102 {
103 KHR_ICD_TRACE("failed to get extension function address clIcdGetPlatformIDsKHR\n");
104 goto Done;
105 }
106
107 // query the number of platforms available and allocate space to store them
108 result = p_clIcdGetPlatformIDs(0, NULL, &platformCount);
109 if (CL_SUCCESS != result)
110 {
111 KHR_ICD_TRACE("failed clIcdGetPlatformIDs\n");
112 goto Done;
113 }
114 platforms = (cl_platform_id *)malloc(platformCount * sizeof(cl_platform_id) );
115 if (!platforms)
116 {
117 KHR_ICD_TRACE("failed to allocate memory\n");
118 goto Done;
119 }
120 memset(platforms, 0, platformCount * sizeof(cl_platform_id) );
121 result = p_clIcdGetPlatformIDs(platformCount, platforms, NULL);
122 if (CL_SUCCESS != result)
123 {
124 KHR_ICD_TRACE("failed clIcdGetPlatformIDs\n");
125 goto Done;
126 }
127
128 // for each platform, add it
129 for (i = 0; i < platformCount; ++i)
130 {
131 KHRicdVendor* vendor = NULL;
132 char *suffix;
133 size_t suffixSize;
134
135 // call clGetPlatformInfo on the returned platform to get the suffix
136 if (!platforms[i])
137 {
138 continue;
139 }
140 result = platforms[i]->dispatch->clGetPlatformInfo(
141 platforms[i],
142 CL_PLATFORM_ICD_SUFFIX_KHR,
143 0,
144 NULL,
145 &suffixSize);
146 if (CL_SUCCESS != result)
147 {
148 continue;
149 }
150 suffix = (char *)malloc(suffixSize);
151 if (!suffix)
152 {
153 continue;
154 }
155 result = platforms[i]->dispatch->clGetPlatformInfo(
156 platforms[i],
157 CL_PLATFORM_ICD_SUFFIX_KHR,
158 suffixSize,
159 suffix,
160 NULL);
161 if (CL_SUCCESS != result)
162 {
163 free(suffix);
164 continue;
165 }
166
167 // allocate a structure for the vendor
168 vendor = (KHRicdVendor*)malloc(sizeof(*vendor) );
169 if (!vendor)
170 {
171 free(suffix);
172 KHR_ICD_TRACE("failed to allocate memory\n");
173 continue;
174 }
175 memset(vendor, 0, sizeof(*vendor) );
176
177 // populate vendor data
178 vendor->library = khrIcdOsLibraryLoad(libraryName);
179 if (!vendor->library)
180 {
181 free(suffix);
182 free(vendor);
183 KHR_ICD_TRACE("failed get platform handle to library\n");
184 continue;
185 }
186 vendor->clGetExtensionFunctionAddress = p_clGetExtensionFunctionAddress;
187 vendor->platform = platforms[i];
188 vendor->suffix = suffix;
189
190 // add this vendor to the list of vendors at the tail
191 {
192 KHRicdVendor **prevNextPointer = NULL;
193 for (prevNextPointer = &khrIcdVendors; *prevNextPointer; prevNextPointer = &( (*prevNextPointer)->next) );
194 *prevNextPointer = vendor;
195 }
196
197 KHR_ICD_TRACE("successfully added vendor %s with suffix %s\n", libraryName, suffix);
198
199 }
200
201 Done:
202
203 if (library)
204 {
205 khrIcdOsLibraryUnload(library);
206 }
207 if (platforms)
208 {
209 free(platforms);
210 }
211 }
212
213 #if defined(CL_ENABLE_LAYERS)
khrIcdLayerAdd(const char * libraryName)214 void khrIcdLayerAdd(const char *libraryName)
215 {
216 void *library = NULL;
217 cl_int result = CL_SUCCESS;
218 pfn_clGetLayerInfo p_clGetLayerInfo = NULL;
219 pfn_clInitLayer p_clInitLayer = NULL;
220 struct KHRLayer *layerIterator = NULL;
221 struct KHRLayer *layer = NULL;
222 cl_layer_api_version api_version = 0;
223 const struct _cl_icd_dispatch *targetDispatch = NULL;
224 const struct _cl_icd_dispatch *layerDispatch = NULL;
225 cl_uint layerDispatchNumEntries = 0;
226 cl_uint loaderDispatchNumEntries = 0;
227
228 // require that the library name be valid
229 if (!libraryName)
230 {
231 goto Done;
232 }
233 KHR_ICD_TRACE("attempting to add layer %s...\n", libraryName);
234
235 // load its library and query its function pointers
236 library = khrIcdOsLibraryLoad(libraryName);
237 if (!library)
238 {
239 KHR_ICD_TRACE("failed to load library %s\n", libraryName);
240 goto Done;
241 }
242
243 // ensure that we haven't already loaded this layer
244 for (layerIterator = khrFirstLayer; layerIterator; layerIterator = layerIterator->next)
245 {
246 if (layerIterator->library == library)
247 {
248 KHR_ICD_TRACE("already loaded layer %s, nothing to do here\n", libraryName);
249 goto Done;
250 }
251 }
252
253 // get the library's clGetLayerInfo pointer
254 p_clGetLayerInfo = (pfn_clGetLayerInfo)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clGetLayerInfo");
255 if (!p_clGetLayerInfo)
256 {
257 KHR_ICD_TRACE("failed to get function address clGetLayerInfo\n");
258 goto Done;
259 }
260
261 // use that function to get the clInitLayer function pointer
262 p_clInitLayer = (pfn_clInitLayer)(size_t)khrIcdOsLibraryGetFunctionAddress(library, "clInitLayer");
263 if (!p_clInitLayer)
264 {
265 KHR_ICD_TRACE("failed to get function address clInitLayer\n");
266 goto Done;
267 }
268
269 result = p_clGetLayerInfo(CL_LAYER_API_VERSION, sizeof(api_version), &api_version, NULL);
270 if (CL_SUCCESS != result)
271 {
272 KHR_ICD_TRACE("failed to query layer version\n");
273 goto Done;
274 }
275
276 if (CL_LAYER_API_VERSION_100 != api_version)
277 {
278 KHR_ICD_TRACE("unsupported api version\n");
279 goto Done;
280 }
281
282 layer = (struct KHRLayer*)calloc(sizeof(struct KHRLayer), 1);
283 if (!layer)
284 {
285 KHR_ICD_TRACE("failed to allocate memory\n");
286 goto Done;
287 }
288 #ifdef CL_LAYER_INFO
289 {
290 // Not using strdup as it is not standard c
291 size_t sz_name = strlen(libraryName) + 1;
292 layer->libraryName = malloc(sz_name);
293 if (!layer->libraryName)
294 {
295 KHR_ICD_TRACE("failed to allocate memory\n");
296 goto Done;
297 }
298 memcpy(layer->libraryName, libraryName, sz_name);
299 layer->p_clGetLayerInfo = (void *)(size_t)p_clGetLayerInfo;
300 }
301 #endif
302
303 if (khrFirstLayer) {
304 targetDispatch = &(khrFirstLayer->dispatch);
305 } else {
306 targetDispatch = &khrMasterDispatch;
307 }
308
309 loaderDispatchNumEntries = sizeof(khrMasterDispatch)/sizeof(void*);
310 result = p_clInitLayer(
311 loaderDispatchNumEntries,
312 targetDispatch,
313 &layerDispatchNumEntries,
314 &layerDispatch);
315 if (CL_SUCCESS != result)
316 {
317 KHR_ICD_TRACE("failed to initialize layer\n");
318 goto Done;
319 }
320
321 layer->next = khrFirstLayer;
322 khrFirstLayer = layer;
323 layer->library = library;
324
325 cl_uint limit = layerDispatchNumEntries < loaderDispatchNumEntries ? layerDispatchNumEntries : loaderDispatchNumEntries;
326
327 for (cl_uint i = 0; i < limit; i++) {
328 ((void **)&(layer->dispatch))[i] =
329 ((void **)layerDispatch)[i] ?
330 ((void **)layerDispatch)[i] : ((void **)targetDispatch)[i];
331 }
332 for (cl_uint i = limit; i < loaderDispatchNumEntries; i++) {
333 ((void **)&(layer->dispatch))[i] = ((void **)targetDispatch)[i];
334 }
335
336 KHR_ICD_TRACE("successfully added layer %s\n", libraryName);
337 return;
338 Done:
339 if (library)
340 {
341 khrIcdOsLibraryUnload(library);
342 }
343 if (layer)
344 {
345 free(layer);
346 }
347 }
348 #endif // defined(CL_ENABLE_LAYERS)
349
350 // Get next file or dirname given a string list or registry key path.
351 // Note: the input string may be modified!
loader_get_next_path(char * path)352 static char *loader_get_next_path(char *path) {
353 size_t len;
354 char *next;
355
356 if (path == NULL) return NULL;
357 next = strchr(path, PATH_SEPARATOR);
358 if (next == NULL) {
359 len = strlen(path);
360 next = path + len;
361 } else {
362 *next = '\0';
363 next++;
364 }
365
366 return next;
367 }
368
khrIcdVendorsEnumerateEnv(void)369 void khrIcdVendorsEnumerateEnv(void)
370 {
371 char* icdFilenames = khrIcd_secure_getenv("OCL_ICD_FILENAMES");
372 char* cur_file = NULL;
373 char* next_file = NULL;
374 if (icdFilenames)
375 {
376 KHR_ICD_TRACE("Found OCL_ICD_FILENAMES environment variable.\n");
377
378 next_file = icdFilenames;
379 while (NULL != next_file && *next_file != '\0') {
380 cur_file = next_file;
381 next_file = loader_get_next_path(cur_file);
382
383 khrIcdVendorAdd(cur_file);
384 }
385
386 khrIcd_free_getenv(icdFilenames);
387 }
388 }
389
390 #if defined(CL_ENABLE_LAYERS)
khrIcdLayersEnumerateEnv(void)391 void khrIcdLayersEnumerateEnv(void)
392 {
393 char* layerFilenames = khrIcd_secure_getenv("OPENCL_LAYERS");
394 char* cur_file = NULL;
395 char* next_file = NULL;
396 if (layerFilenames)
397 {
398 KHR_ICD_TRACE("Found OPENCL_LAYERS environment variable.\n");
399
400 next_file = layerFilenames;
401 while (NULL != next_file && *next_file != '\0') {
402 cur_file = next_file;
403 next_file = loader_get_next_path(cur_file);
404
405 khrIcdLayerAdd(cur_file);
406 }
407
408 khrIcd_free_getenv(layerFilenames);
409 }
410 }
411 #endif // defined(CL_ENABLE_LAYERS)
412
khrIcdContextPropertiesGetPlatform(const cl_context_properties * properties,cl_platform_id * outPlatform)413 void khrIcdContextPropertiesGetPlatform(const cl_context_properties *properties, cl_platform_id *outPlatform)
414 {
415 if (properties == NULL && khrIcdVendors != NULL)
416 {
417 *outPlatform = khrIcdVendors[0].platform;
418 }
419 else
420 {
421 const cl_context_properties *property = (cl_context_properties *)NULL;
422 *outPlatform = NULL;
423 for (property = properties; property && property[0]; property += 2)
424 {
425 if ((cl_context_properties)CL_CONTEXT_PLATFORM == property[0])
426 {
427 *outPlatform = (cl_platform_id)property[1];
428 }
429 }
430 }
431 }
432
433