Default platform is now specified
[ocl-icd] / ocl_icd_loader.c
1 /**
2 Copyright (c) 2012, Brice Videau <brice.videau@imag.fr>
3 Copyright (c) 2012, Vincent Danjean <Vincent.Danjean@ens-lyon.org>
4 All rights reserved.
5       
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8     
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.
14         
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.
25 */
26
27 #include <dirent.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <dlfcn.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include "config.h"
37 #ifdef USE_PTHREAD
38 #  include <pthread.h>
39 #endif
40 #pragma GCC diagnostic push
41 #  pragma GCC diagnostic ignored "-Wcpp"
42 #  define CL_USE_DEPRECATED_OPENCL_1_1_APIS
43 #  include <CL/opencl.h>
44 #pragma GCC diagnostic pop
45
46 #pragma GCC visibility push(hidden)
47
48 #include "ocl_icd_loader.h"
49 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
50 #include "ocl_icd_debug.h"
51
52 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
53
54 int debug_ocl_icd_mask=0;
55
56 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
57 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
58
59
60 struct vendor_icd {
61   cl_uint       num_platforms;
62   cl_uint       first_platform;
63   void *        dl_handle;
64   clGetExtensionFunctionAddress_fn ext_fn_ptr;
65 };
66
67 struct platform_icd {
68   char *         extension_suffix;
69   char *         version;
70   struct vendor_icd *vicd;
71   cl_platform_id pid;
72 };
73
74 struct vendor_icd *_icds=NULL;
75 struct platform_icd *_picds=NULL;
76 static cl_uint _num_icds = 0;
77 static cl_uint _num_picds = 0;
78
79 #ifdef DEBUG_OCL_ICD
80 #  define _clS(x) [-x] = #x
81 #  define MAX_CL_ERRORS (-CL_INVALID_DEVICE_PARTITION_COUNT)
82 static char const * const clErrorStr[MAX_CL_ERRORS+1] = {
83   _clS(CL_SUCCESS),
84   _clS(CL_DEVICE_NOT_FOUND),
85   _clS(CL_DEVICE_NOT_AVAILABLE),
86   _clS(CL_COMPILER_NOT_AVAILABLE),
87   _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
88   _clS(CL_OUT_OF_RESOURCES),
89   _clS(CL_OUT_OF_HOST_MEMORY),
90   _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
91   _clS(CL_MEM_COPY_OVERLAP),
92   _clS(CL_IMAGE_FORMAT_MISMATCH),
93   _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
94   _clS(CL_BUILD_PROGRAM_FAILURE),
95   _clS(CL_MAP_FAILURE),
96   _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
97   _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
98   _clS(CL_COMPILE_PROGRAM_FAILURE),
99   _clS(CL_LINKER_NOT_AVAILABLE),
100   _clS(CL_LINK_PROGRAM_FAILURE),
101   _clS(CL_DEVICE_PARTITION_FAILED),
102   _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
103   _clS(CL_INVALID_VALUE),
104   _clS(CL_INVALID_DEVICE_TYPE),
105   _clS(CL_INVALID_PLATFORM),
106   _clS(CL_INVALID_DEVICE),
107   _clS(CL_INVALID_CONTEXT),
108   _clS(CL_INVALID_QUEUE_PROPERTIES),
109   _clS(CL_INVALID_COMMAND_QUEUE),
110   _clS(CL_INVALID_HOST_PTR),
111   _clS(CL_INVALID_MEM_OBJECT),
112   _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
113   _clS(CL_INVALID_IMAGE_SIZE),
114   _clS(CL_INVALID_SAMPLER),
115   _clS(CL_INVALID_BINARY),
116   _clS(CL_INVALID_BUILD_OPTIONS),
117   _clS(CL_INVALID_PROGRAM),
118   _clS(CL_INVALID_PROGRAM_EXECUTABLE),
119   _clS(CL_INVALID_KERNEL_NAME),
120   _clS(CL_INVALID_KERNEL_DEFINITION),
121   _clS(CL_INVALID_KERNEL),
122   _clS(CL_INVALID_ARG_INDEX),
123   _clS(CL_INVALID_ARG_VALUE),
124   _clS(CL_INVALID_ARG_SIZE),
125   _clS(CL_INVALID_KERNEL_ARGS),
126   _clS(CL_INVALID_WORK_DIMENSION),
127   _clS(CL_INVALID_WORK_GROUP_SIZE),
128   _clS(CL_INVALID_WORK_ITEM_SIZE),
129   _clS(CL_INVALID_GLOBAL_OFFSET),
130   _clS(CL_INVALID_EVENT_WAIT_LIST),
131   _clS(CL_INVALID_EVENT),
132   _clS(CL_INVALID_OPERATION),
133   _clS(CL_INVALID_GL_OBJECT),
134   _clS(CL_INVALID_BUFFER_SIZE),
135   _clS(CL_INVALID_MIP_LEVEL),
136   _clS(CL_INVALID_GLOBAL_WORK_SIZE),
137   _clS(CL_INVALID_PROPERTY),
138   _clS(CL_INVALID_IMAGE_DESCRIPTOR),
139   _clS(CL_INVALID_COMPILER_OPTIONS),
140   _clS(CL_INVALID_LINKER_OPTIONS),
141   _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
142 };
143 #undef _clS
144 #endif
145
146 static char* _clerror2string (cl_int error) __attribute__((unused));
147 static char* _clerror2string (cl_int error) {
148 #ifdef DEBUG_OCL_ICD
149   if (-error > MAX_CL_ERRORS || error > 0) {
150     debug(D_WARN, "Unknown error code %d", error);
151     RETURN_STR("OpenCL Error");
152   }
153   const char *ret=clErrorStr[-error];
154   if (ret == NULL) {
155     debug(D_WARN, "Unknown error code %d", error);
156     RETURN_STR("OpenCL Error");
157   }
158   RETURN_STR(ret);
159 #else
160   static char number[15];
161   if (error==0) {
162     RETURN_STR("CL_SUCCESS");
163   }
164   snprintf(number, 15, "%i", error);
165   RETURN_STR(number);
166 #endif
167 }
168
169 static inline int _string_end_with_icd(const char* str) {
170   size_t len = strlen(str);
171   if( len<5 || strcmp(str + len - 4, ".icd" ) != 0 ) {
172     return 0;
173   }
174   return 1;
175 }
176
177 static inline int _string_with_slash(const char* str) {
178   return strchr(str, '/') != NULL;
179 }
180
181 static inline unsigned int _find_num_icds(DIR *dir) {
182   unsigned int num_icds = 0;
183   struct dirent *ent;
184   while( (ent=readdir(dir)) != NULL ){
185     if (_string_end_with_icd(ent->d_name)) {
186       num_icds++;
187     }
188   }
189   rewinddir(dir);
190   RETURN(num_icds);
191 }
192
193 static inline unsigned int _load_icd(int num_icds, const char* lib_path) {
194   unsigned int ret=0;
195   debug(D_LOG, "Loading ICD '%s'", lib_path);
196
197   _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
198   if(_icds[num_icds].dl_handle != NULL) {
199     debug(D_LOG, "ICD[%i] loaded", num_icds);
200     ret=1;
201   } else {
202     debug(D_WARN, "error while dlopening the IDL: '%s',\n  => skipping ICD", dlerror());
203   }
204   return ret;
205 }
206
207 static inline unsigned int _open_driver(unsigned int num_icds,
208                                         const char*dir_path, const char*file_path) {
209   char * lib_path;
210   char * err;
211   unsigned int lib_path_length;
212   if (dir_path != NULL) {
213     lib_path_length = strlen(dir_path) + strlen(file_path) + 2;
214     lib_path = malloc(lib_path_length*sizeof(char));
215     sprintf(lib_path,"%s/%s", dir_path, file_path);
216   } else {
217     lib_path_length = strlen(file_path) + 1;
218     lib_path = malloc(lib_path_length*sizeof(char));
219     sprintf(lib_path,"%s", file_path);
220   }
221   debug(D_LOG, "Considering file '%s'", lib_path);
222   FILE *f = fopen(lib_path,"r");
223   free(lib_path);
224   if (f==NULL) {
225     RETURN(num_icds);
226   }
227   
228   fseek(f, 0, SEEK_END);
229   lib_path_length = ftell(f)+1;
230   fseek(f, 0, SEEK_SET);
231   if(lib_path_length == 1) {
232     debug(D_WARN, "File contents too short, skipping ICD");
233     fclose(f);
234     RETURN(num_icds);
235   }
236   lib_path = malloc(lib_path_length*sizeof(char));
237   err = fgets(lib_path, lib_path_length, f);
238   fclose(f);
239   if( err == NULL ) {
240     free(lib_path);
241     debug(D_WARN, "Error while loading file contents, skipping ICD");
242     RETURN(num_icds);
243   }
244
245   lib_path_length = strlen(lib_path);
246   
247   if( lib_path[lib_path_length-1] == '\n' )
248     lib_path[lib_path_length-1] = '\0';
249
250   num_icds += _load_icd(num_icds, lib_path);
251
252   free(lib_path);
253   RETURN(num_icds);
254 }
255
256 static inline unsigned int _open_drivers(DIR *dir, const char* dir_path) {
257   unsigned int num_icds = 0;
258   struct dirent *ent;
259   while( (ent=readdir(dir)) != NULL ){
260     if(! _string_end_with_icd(ent->d_name)) {
261       continue;
262     }
263     num_icds = _open_driver(num_icds, dir_path, ent->d_name);
264
265   }
266   RETURN(num_icds);
267 }
268
269 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
270   void *addr1;
271   debug(D_LOG,"Looking for function %s",name);
272   addr1=dlsym(dlh, name);
273   if (addr1 == NULL) {
274     debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
275   }
276   void* addr2=NULL;
277   if (fn) {
278     addr2=(*fn)(name);
279     if (addr2 == NULL) {
280       debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
281     }
282 #ifdef DEBUG_OCL_ICD
283     if (addr1 && addr2 && addr1!=addr2) {
284       debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
285     }
286 #endif
287   }
288   if (!addr2) addr2=addr1;
289   RETURN(addr2);
290 }
291
292 static int _allocate_platforms(int req) {
293   static cl_uint allocated=0;
294   debug(D_LOG,"Requesting allocation for %d platforms",req);
295   if (allocated - _num_picds < req) {
296     if (allocated==0) {
297       _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
298     } else {
299       req = req - (allocated - _num_picds);
300       _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
301     }
302     allocated += req;
303   }
304   RETURN(allocated - _num_picds);
305 }
306
307 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
308                  cl_platform_id pid, cl_platform_info cname, char* sname) {
309   cl_int error;
310   size_t param_value_size_ret;
311   error = plt_info_ptr(pid, cname, 0, NULL, &param_value_size_ret);
312   if (error != CL_SUCCESS) {
313     debug(D_WARN, "Error %s while requesting %s in platform %p",
314           _clerror2string(error), sname, pid);
315     return NULL;
316   }
317   char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
318   if (param_value == NULL) {
319     debug(D_WARN, "Error in malloc while requesting %s in platform %p",
320           sname, pid);
321     return NULL;
322   }
323   error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
324   if (error != CL_SUCCESS){
325     free(param_value);
326     debug(D_WARN, "Error %s while requesting %s in platform %p",
327           _clerror2string(error), sname, pid);
328     return NULL;
329   }
330   RETURN_STR(param_value);
331 }
332
333 static inline void _find_and_check_platforms(cl_uint num_icds) {
334   cl_uint i;
335   _num_icds = 0;
336   for( i=0; i<num_icds; i++){
337     debug(D_LOG, "Checking ICD %i", i);
338     struct vendor_icd *picd = &_icds[_num_icds];
339     void* dlh = _icds[i].dl_handle;
340     picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
341     clIcdGetPlatformIDsKHR_fn plt_fn_ptr = 
342       _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
343     clGetPlatformInfo_fn plt_info_ptr = 
344       _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
345     if( picd->ext_fn_ptr == NULL
346         || plt_fn_ptr == NULL
347         || plt_info_ptr == NULL) {
348       debug(D_WARN, "Missing symbols in ICD, skipping it");
349       continue;
350     }
351     cl_uint num_platforms=0;
352     cl_int error;
353     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
354     if( error != CL_SUCCESS || num_platforms == 0) {
355       debug(D_LOG, "No platform in ICD, skipping it");
356       continue;
357     }
358     cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
359     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
360     if( error != CL_SUCCESS ){
361       free(platforms);
362       debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
363       continue;
364     }
365     cl_uint num_valid_platforms=0;
366     cl_uint j;
367     debug(D_LOG, "Try to load %d plateforms", num_platforms);
368     if (_allocate_platforms(num_platforms) < num_platforms) {
369       free(platforms);
370       debug(D_WARN, "Not enought platform allocated. Skipping ICD");
371       continue;
372     }
373     for(j=0; j<num_platforms; j++) {
374       debug(D_LOG, "Checking platform %i", j);
375       struct platform_icd *p=&_picds[_num_picds];
376       char *param_value=NULL;
377       p->extension_suffix=NULL;
378       p->vicd=&_icds[i];
379       p->pid=platforms[j];
380 #ifdef DEBUG_OCL_ICD
381       if (debug_ocl_icd_mask & D_DUMP) {
382         int log=debug_ocl_icd_mask & D_TRACE;
383         debug_ocl_icd_mask &= ~D_TRACE;
384         dump_platform(p->vicd->ext_fn_ptr, p->pid);
385         debug_ocl_icd_mask |= log;
386       }
387 #endif
388       {
389               /* Allow to workaround a bug in the Intel ICD used
390                * with optirun (search for NVidia Optimus for more info)
391                */
392               const char* str=getenv("OCL_ICD_ASSUME_ICD_EXTENSION");
393               if (! str || str[0]==0) {
394                       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
395                       if (param_value == NULL){
396                               debug(D_WARN, "Skipping platform %i", j);
397                               continue;
398                       }
399                       debug(D_DUMP, "Supported extensions: %s", param_value);
400                       if( strstr(param_value, "cl_khr_icd") == NULL){
401                               free(param_value); 
402                               debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
403                               continue;
404                       }
405                       free(param_value);
406               }
407       }
408       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
409       if (param_value == NULL){
410         debug(D_WARN, "Skipping platform %i", j);
411         continue;
412       }
413       p->extension_suffix = param_value;
414       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
415 #ifdef DEBUG_OCL_ICD
416       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
417       if (param_value != NULL){
418         debug(D_DUMP, "Profile: %s", param_value);
419         free(param_value);
420       }
421       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
422       p->version = param_value;
423       if (param_value != NULL){
424         debug(D_DUMP, "Version: %s", param_value);
425         free(param_value);
426       }
427       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
428       if (param_value != NULL){
429         debug(D_DUMP, "Name: %s", param_value);
430         free(param_value);
431       }
432       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
433       if (param_value != NULL){
434         debug(D_DUMP, "Vendor: %s", param_value);
435         free(param_value);
436       }
437 #endif
438       num_valid_platforms++;
439       _num_picds++;
440     }
441     if( num_valid_platforms != 0 ) {
442       if ( _num_icds != i ) {
443         picd->dl_handle = dlh;
444       }
445       _num_icds++;
446       picd->num_platforms = num_valid_platforms;
447       _icds[i].first_platform = _num_picds - num_valid_platforms;
448     } else {
449       dlclose(dlh);
450     }
451     free(platforms);
452   }
453 }
454
455 static void __initClIcd( void ) {
456   debug_init();
457   cl_uint num_icds = 0;
458   int is_dir = 0;
459   DIR *dir;
460   const char* dir_path=getenv("OCL_ICD_VENDORS");
461   if (! dir_path || dir_path[0]==0) {
462     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
463     dir_path=ETC_OPENCL_VENDORS;
464     is_dir=1;
465   }
466   if (!is_dir) {
467     struct stat buf;
468     int ret=stat(dir_path, &buf);
469     if (ret != 0 && errno != ENOENT) {
470       debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
471     }
472     if (ret == 0 && S_ISDIR(buf.st_mode)) {
473       is_dir=1;
474     }
475   }
476   
477   if (!is_dir) {
478     debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
479     num_icds = 1;
480     dir=NULL;
481   } else {
482     debug(D_LOG,"Reading icd list from '%s'", dir_path);
483     dir = opendir(dir_path);
484     if(dir == NULL) {
485       if (errno == ENOTDIR) {
486         debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
487         dir_path);
488       }
489       goto abort;
490     }
491
492     num_icds = _find_num_icds(dir);
493     if(num_icds == 0) {
494       goto abort;
495     }
496   }
497
498   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
499   if (_icds == NULL) {
500     goto abort;
501   }
502   
503   if (!is_dir) {
504     if (_string_end_with_icd(dir_path)) {
505       num_icds = 0;
506       if (! _string_with_slash(dir_path)) {
507         num_icds = _open_driver(0, ETC_OPENCL_VENDORS, dir_path);
508       }
509       if (num_icds == 0) {
510         num_icds = _open_driver(0, NULL, dir_path);
511       }
512     } else {
513       num_icds = _load_icd(0, dir_path);
514     }
515   } else {
516     num_icds = _open_drivers(dir, dir_path);
517   }
518   if(num_icds == 0) {
519     goto abort;
520   }
521
522   _find_and_check_platforms(num_icds);
523   if(_num_icds == 0){
524     goto abort;
525   }
526
527   if (_num_icds < num_icds) {
528     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
529   }
530   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
531   return;
532  abort:
533   _num_icds = 0;
534   if (_icds) {
535     free(_icds);
536     _icds = NULL;
537   }
538   return;
539 }
540
541 #ifdef USE_PTHREAD
542 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
543 #else
544 static int gard=0;
545 #endif
546 volatile static __thread int in_init = 0;
547 volatile static cl_uint _initialized = 0;
548
549 static inline void __attribute__((constructor)) _initClIcd( void ) {
550   if( _initialized )
551     return;
552 #ifdef USE_PTHREAD
553   if (in_init) {
554     /* probably reentrency */
555   } else {
556     in_init=1;
557     __sync_synchronize();
558     pthread_once(&once_init, &__initClIcd);
559     __sync_synchronize();
560     in_init=0;
561   }
562 #else
563   if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
564     in_init=1;
565     __sync_synchronize();
566     __initClIcd();
567     __sync_synchronize();
568     in_init=0;
569   } else {
570     if (in_init) {
571       /* probably reentrency (could also be user threads). */
572     } else {
573       /* someone else started __initClIcd(). We wait until its end. */
574       debug(D_WARN, "Waiting end of init");
575       while (!_initialized) ;
576       debug(D_WARN, "Wait done");
577    }
578   }
579 #endif
580   _initialized = 1;
581 }
582
583 #pragma GCC visibility pop
584 #define hidden_alias(name) \
585   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
586
587 typedef enum {
588   CL_ICDL_OCL_VERSION=1,
589   CL_ICDL_VERSION=2,
590   CL_ICDL_NAME=3,
591   CL_ICDL_VENDOR=4,
592 } cl_icdl_info;
593
594 static cl_int clGetICDLoaderInfoOCLICD(
595   cl_icdl_info     param_name,
596   size_t           param_value_size, 
597   void *           param_value,
598   size_t *         param_value_size_ret)
599 {
600   char cl_icdl_ocl_version[] = "OpenCL 1.2";
601   char cl_icdl_version[] = PACKAGE_VERSION;
602   char cl_icdl_name[] = PACKAGE_NAME;
603   char cl_icdl_vendor[] = "OCL Icd free software";
604
605   size_t size_string;
606   char * string_p;
607 #define oclcase(name, NAME) \
608   case CL_ICDL_##NAME: \
609     string_p = cl_icdl_##name; \
610     size_string = sizeof(cl_icdl_##name); \
611     break
612
613   switch ( param_name ) {
614     oclcase(ocl_version,OCL_VERSION);
615     oclcase(version,VERSION);
616     oclcase(name,NAME);
617     oclcase(vendor,VENDOR);
618     default:
619       return CL_INVALID_VALUE;
620       break;
621   }
622 #undef oclcase
623   if( param_value != NULL ) {
624     if( size_string > param_value_size )
625       return CL_INVALID_VALUE;
626     memcpy(param_value, string_p, size_string);
627   }
628   if( param_value_size_ret != NULL )
629     *param_value_size_ret = size_string;
630   return CL_SUCCESS;
631 }
632
633 CL_API_ENTRY void * CL_API_CALL
634 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
635   debug_trace();
636   _initClIcd();
637   if( func_name == NULL )
638     return NULL;
639   cl_uint suffix_length;
640   cl_uint i;
641   void * return_value=NULL;
642   struct func_desc const * fn=&function_description[0];
643   int lenfn=strlen(func_name);
644   if (lenfn > 3 &&
645       (strcmp(func_name+lenfn-3, "KHR")==0 || strcmp(func_name+lenfn-3, "EXT")==0)) {
646     while (fn->name != NULL) {
647       if (strcmp(func_name, fn->name)==0)
648         RETURN(fn->addr);
649       fn++;
650     }
651   }
652   for(i=0; i<_num_picds; i++) {
653     suffix_length = strlen(_picds[i].extension_suffix);
654     if( suffix_length > strlen(func_name) )
655       continue;
656     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
657       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
658   }
659   if(strcmp(func_name, "clGetICDLoaderInfoOCLICD") == 0) {
660     return (void*)(void*(*)(void))(&clGetICDLoaderInfoOCLICD);
661   }
662   RETURN(return_value);
663 }
664 hidden_alias(clGetExtensionFunctionAddress);
665
666 CL_API_ENTRY cl_int CL_API_CALL
667 clGetPlatformIDs(cl_uint          num_entries,
668                  cl_platform_id * platforms,
669                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
670   debug_trace();
671   _initClIcd();
672   if( platforms == NULL && num_platforms == NULL )
673     RETURN(CL_INVALID_VALUE);
674   if( num_entries == 0 && platforms != NULL )
675     RETURN(CL_INVALID_VALUE);
676   if( _num_icds == 0)
677     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
678
679   cl_uint i;
680   if( num_platforms != NULL ){
681     *num_platforms = _num_picds;
682   }
683   if( platforms != NULL ) {
684     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
685     for( i=0; i<n_platforms; i++) {
686       *(platforms++) = _picds[i].pid;
687     }
688   }
689   return CL_SUCCESS;
690 }
691 hidden_alias(clGetPlatformIDs);
692
693 CL_API_ENTRY cl_context CL_API_CALL
694 clCreateContext(const cl_context_properties *  properties ,
695                 cl_uint                        num_devices ,
696                 const cl_device_id *           devices ,
697                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
698                 void *                         user_data ,
699                 cl_int *                       errcode_ret ){
700   debug_trace();
701   _initClIcd();
702   cl_uint i=0;
703   if( properties != NULL){
704     while( properties[i] != 0 ) {
705       if( properties[i] == CL_CONTEXT_PLATFORM )
706         RETURN(((struct _cl_platform_id *) properties[i+1])
707           ->dispatch->clCreateContext(properties, num_devices, devices,
708                         pfn_notify, user_data, errcode_ret));
709       i += 2;
710     }
711   }
712   if(devices == NULL || num_devices == 0) {
713     if(errcode_ret) {
714       *errcode_ret = CL_INVALID_VALUE;
715     }
716     RETURN(NULL);
717   }
718   RETURN(((struct _cl_device_id *)devices[0])
719     ->dispatch->clCreateContext(properties, num_devices, devices,
720                   pfn_notify, user_data, errcode_ret));
721 }
722 hidden_alias(clCreateContext);
723
724 CL_API_ENTRY cl_context CL_API_CALL
725 clCreateContextFromType(const cl_context_properties *  properties ,
726                         cl_device_type                 device_type ,
727                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
728                         void *                         user_data ,
729                         cl_int *                       errcode_ret ){
730   debug_trace();
731   _initClIcd();
732   cl_uint i=0;
733   if( properties != NULL){
734     while( properties[i] != 0 ) {
735       if( properties[i] == CL_CONTEXT_PLATFORM )
736         if (properties[i+1] == 0) {
737           goto out;
738         }
739         return ((struct _cl_platform_id *) properties[i+1])
740           ->dispatch->clCreateContextFromType(properties, device_type,
741                         pfn_notify, user_data, errcode_ret);
742       i += 2;
743     }
744   } else {
745     if(_num_picds == 0) {
746       if(errcode_ret) {
747         *errcode_ret = CL_INVALID_VALUE;
748       }
749       RETURN(NULL);
750     }
751     const char *default_platform = getenv("OPENCL_ICD_DEFAULT_PLATFORM");
752     int num_default_platform;
753     char *end_scan;
754     if (! default_platform) {
755       num_default_platform = 0;
756     } else {
757       num_default_platform = strtol(default_platform, &end_scan, 10);
758       if (*default_platform == '\0' || *end_scan != '\0') {
759         goto out;
760       }
761     }
762     if (num_default_platform < 0 || num_default_platform >= _num_picds) {
763       goto out;
764     }
765     RETURN(_picds[num_default_platform].pid->dispatch->clCreateContextFromType
766         (properties, device_type, pfn_notify, user_data, errcode_ret));
767   }
768  out:
769   if(errcode_ret) {
770     *errcode_ret = CL_INVALID_PLATFORM;
771   }
772   RETURN(NULL);
773 }
774 hidden_alias(clCreateContextFromType);
775
776 CL_API_ENTRY cl_int CL_API_CALL
777 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
778                       cl_gl_context_info             param_name ,
779                       size_t                         param_value_size ,
780                       void *                         param_value ,
781                       size_t *                       param_value_size_ret ){
782   debug_trace();
783   _initClIcd();
784   cl_uint i=0;
785   if( properties != NULL){
786     while( properties[i] != 0 ) {
787       if( properties[i] == CL_CONTEXT_PLATFORM )
788         RETURN(((struct _cl_platform_id *) properties[i+1])
789           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
790                         param_value_size, param_value, param_value_size_ret));
791       i += 2;
792     }
793   }
794   RETURN(CL_INVALID_PLATFORM);
795 }
796 hidden_alias(clGetGLContextInfoKHR);
797
798 CL_API_ENTRY cl_int CL_API_CALL
799 clWaitForEvents(cl_uint              num_events ,
800                 const cl_event *     event_list ){
801   debug_trace();
802   if( num_events == 0 || event_list == NULL )
803     RETURN(CL_INVALID_VALUE);
804   RETURN(((struct _cl_event *)event_list[0])
805     ->dispatch->clWaitForEvents(num_events, event_list));
806 }
807 hidden_alias(clWaitForEvents);
808
809 CL_API_ENTRY cl_int CL_API_CALL
810 clUnloadCompiler( void ){
811   debug_trace();
812   RETURN(CL_SUCCESS);
813 }
814 hidden_alias(clUnloadCompiler);