xref: /aosp_15_r20/external/OpenCL-ICD-Loader/loader/icd.c (revision 1cddb830dba8aa7c1cc1039338e56b3b9fa24952)
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