2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 1. Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #define CL_USE_DEPRECATED_OPENCL_1_1_APIS
33 #include <CL/opencl.h>
35 #pragma GCC visibility push(hidden)
37 #include "ocl_icd_loader.h"
39 #define DEBUG_OCL_ICD 1
45 #if defined(DEBUG_OCL_ICD)
46 static int debug_ocl_icd_mask=0;
47 # define debug(mask, fmt, ...) do {\
48 if (debug_ocl_icd_mask & mask) { \
49 fprintf(stderr, "ocl-icd: %s: " fmt "\n", __func__, ##__VA_ARGS__); \
52 # define RETURN(val) do { \
53 __typeof__(val) ret=(val); \
54 debug(D_ARGS, "return: %ld/0x%lx", (long)ret, (long)ret); \
58 # define debug(...) (void)0
59 # define RETURN(val) return (val)
62 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
63 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
67 cl_uint num_platforms;
68 cl_uint first_platform;
70 clGetExtensionFunctionAddress_fn ext_fn_ptr;
74 char * extension_suffix;
75 struct vendor_icd *vicd;
79 struct vendor_icd *_icds=NULL;
80 struct platform_icd *_picds=NULL;
81 static cl_uint _num_icds = 0;
82 static cl_uint _num_picds = 0;
84 static cl_uint _initialized = 0;
86 static const char *_dir_path="/etc/OpenCL/vendors/";
88 static inline cl_uint _find_num_icds(DIR *dir) {
91 while( (ent=readdir(dir)) != NULL ){
92 if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
94 cl_uint d_name_len = strlen(ent->d_name);
95 if( d_name_len>4 && strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
97 // printf("%s%s\n", _dir_path, ent->d_name);
104 static inline cl_uint _open_drivers(DIR *dir) {
105 cl_uint num_icds = 0;
107 while( (ent=readdir(dir)) != NULL ){
108 if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
110 cl_uint d_name_len = strlen(ent->d_name);
111 if( d_name_len>4 && strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
115 unsigned int lib_path_length = strlen(_dir_path) + strlen(ent->d_name) + 1;
116 lib_path = malloc(lib_path_length*sizeof(char));
117 sprintf(lib_path,"%s%s", _dir_path, ent->d_name);
118 FILE *f = fopen(lib_path,"r");
121 fseek(f, 0, SEEK_END);
122 lib_path_length = ftell(f)+1;
123 fseek(f, 0, SEEK_SET);
124 if(lib_path_length == 1) {
128 lib_path = malloc(lib_path_length*sizeof(char));
129 err = fgets(lib_path, lib_path_length, f);
136 lib_path_length = strlen(lib_path);
138 if( lib_path[lib_path_length-1] == '\n' )
139 lib_path[lib_path_length-1] = '\0';
141 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
142 if(_icds[num_icds].dl_handle != NULL) {
143 debug(D_LOG, "Loading ICD[%i] -> '%s'", num_icds, lib_path);
151 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
153 addr1=dlsym(dlh, name);
155 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
161 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
163 #if defined(DEBUG_OCL_ICD)
164 if (addr1 && addr2 && addr1!=addr2) {
165 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
169 if (!addr2) addr2=addr1;
173 static int _allocate_platforms(int req) {
174 static cl_uint allocated=0;
175 debug(D_LOG,"Requesting allocation for %d platforms",req);
176 if (allocated - _num_picds < req) {
178 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
180 req = req - (allocated - _num_picds);
181 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
185 RETURN(allocated - _num_picds);
188 static inline void _find_and_check_platforms(cl_uint num_icds) {
191 for( i=0; i<num_icds; i++){
192 debug(D_LOG, "Checking ICD %i", i);
193 struct vendor_icd *picd = &_icds[_num_icds];
194 void* dlh = _icds[i].dl_handle;
195 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
196 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
197 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
198 clGetPlatformInfo_fn plt_info_ptr =
199 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
200 if( picd->ext_fn_ptr == NULL
201 || plt_fn_ptr == NULL
202 || plt_info_ptr == NULL) {
203 debug(D_WARN, "Missing symbols in ICD, skipping it");
206 cl_uint num_platforms=0;
208 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
209 if( error != CL_SUCCESS || num_platforms == 0) {
210 debug(D_LOG, "No platform in ICD, skipping it");
213 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
214 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
215 if( error != CL_SUCCESS ){
217 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
220 cl_uint num_valid_platforms=0;
222 debug(D_LOG, "Try to load %d plateforms", num_platforms);
223 if (_allocate_platforms(num_platforms) < num_platforms) {
225 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
228 for(j=0; j<num_platforms; j++) {
229 debug(D_LOG, "Checking platform %i", j);
230 size_t param_value_size_ret;
231 struct platform_icd *p=&_picds[_num_picds];
232 p->extension_suffix=NULL;
235 error = plt_info_ptr(p->pid, CL_PLATFORM_EXTENSIONS, 0, NULL, ¶m_value_size_ret);
236 if (error != CL_SUCCESS) {
237 debug(D_WARN, "Error while loading extensions in platform %i, skipping it",j);
240 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
241 error = plt_info_ptr(p->pid, CL_PLATFORM_EXTENSIONS, param_value_size_ret, param_value, NULL);
242 if (error != CL_SUCCESS){
244 debug(D_WARN, "Error while loading extensions in platform %i, skipping it", j);
247 if( strstr(param_value, "cl_khr_icd") == NULL){
249 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
253 error = plt_info_ptr(p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, 0, NULL, ¶m_value_size_ret);
254 if (error != CL_SUCCESS) {
255 debug(D_WARN, "Error while loading suffix in platform %i, skipping it", j);
258 param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
259 error = plt_info_ptr(p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, param_value_size_ret, param_value, NULL);
260 if (error != CL_SUCCESS){
261 debug(D_WARN, "Error while loading suffix in platform %i, skipping it", j);
265 p->extension_suffix = param_value;
266 debug(D_LOG, "Extension suffix: %s", param_value);
267 num_valid_platforms++;
270 if( num_valid_platforms != 0 ) {
271 if ( _num_icds != i ) {
272 picd->dl_handle = dlh;
275 picd->num_platforms = num_valid_platforms;
276 _icds[i].first_platform = _num_picds - num_valid_platforms;
284 static void _initClIcd( void ) {
287 #if defined(DEBUG_OCL_ICD)
288 char *debug=getenv("OCL_ICD_DEBUG");
290 debug_ocl_icd_mask=atoi(debug);
291 if (debug_ocl_icd_mask==0)
292 debug_ocl_icd_mask=1;
295 cl_uint num_icds = 0;
297 dir = opendir(_dir_path);
302 num_icds = _find_num_icds(dir);
307 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
312 num_icds = _open_drivers(dir);
317 _find_and_check_platforms(num_icds);
322 if (_num_icds < num_icds) {
323 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
325 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
338 #pragma GCC visibility pop
340 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
343 if( func_name == NULL )
345 cl_uint suffix_length;
347 void * return_value=NULL;
348 struct func_desc const * fn=&function_description[0];
349 while (fn->name != NULL) {
350 if (strcmp(func_name, fn->name)==0)
354 for(i=0; i<_num_picds; i++) {
355 suffix_length = strlen(_picds[i].extension_suffix);
356 if( suffix_length > strlen(func_name) )
358 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
359 return (*_picds[i].vicd->ext_fn_ptr)(func_name);
363 typeof(clGetExtensionFunctionAddress) clGetExtensionFunctionAddress_hid __attribute__ ((alias ("clGetExtensionFunctionAddress"), visibility("hidden")));
365 CL_API_ENTRY cl_int CL_API_CALL
366 clGetPlatformIDs(cl_uint num_entries,
367 cl_platform_id * platforms,
368 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
371 if( platforms == NULL && num_platforms == NULL )
372 return CL_INVALID_VALUE;
373 if( num_entries == 0 && platforms != NULL )
374 return CL_INVALID_VALUE;
376 return CL_PLATFORM_NOT_FOUND_KHR;
379 if( num_platforms != NULL ){
380 *num_platforms = _num_picds;
382 if( platforms != NULL ) {
383 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
384 for( i=0; i<n_platforms; i++) {
385 *(platforms++) = _picds[i].pid;
390 typeof(clGetPlatformIDs) clGetPlatformIDs_hid __attribute__ ((alias ("clGetPlatformIDs"), visibility("hidden")));