[debug] More debug info
[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 #pragma GCC diagnostic push
33 #  pragma GCC diagnostic ignored "-Wcpp"
34 #  define CL_USE_DEPRECATED_OPENCL_1_1_APIS
35 #  include <CL/opencl.h>
36 #pragma GCC diagnostic pop
37
38 #pragma GCC visibility push(hidden)
39
40 #include "ocl_icd_loader.h"
41 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
42 #include "ocl_icd_debug.h"
43
44 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
45
46 int debug_ocl_icd_mask=0;
47
48 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
49 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
50
51
52 struct vendor_icd {
53   cl_uint       num_platforms;
54   cl_uint       first_platform;
55   void *        dl_handle;
56   clGetExtensionFunctionAddress_fn ext_fn_ptr;
57 };
58
59 struct platform_icd {
60   char *         extension_suffix;
61   char *         version;
62   struct vendor_icd *vicd;
63   cl_platform_id pid;
64 };
65
66 struct vendor_icd *_icds=NULL;
67 struct platform_icd *_picds=NULL;
68 static cl_uint _num_icds = 0;
69 static cl_uint _num_picds = 0;
70
71 static cl_uint _initialized = 0;
72
73 #if DEBUG_OCL_ICD
74 #  define _clS(x) [-x] = #x
75 #  define MAX_CL_ERRORS CL_INVALID_DEVICE_PARTITION_COUNT
76 static char const * const clErrorStr[-MAX_CL_ERRORS+1] = {
77   _clS(CL_SUCCESS),
78   _clS(CL_DEVICE_NOT_FOUND),
79   _clS(CL_DEVICE_NOT_AVAILABLE),
80   _clS(CL_COMPILER_NOT_AVAILABLE),
81   _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
82   _clS(CL_OUT_OF_RESOURCES),
83   _clS(CL_OUT_OF_HOST_MEMORY),
84   _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
85   _clS(CL_MEM_COPY_OVERLAP),
86   _clS(CL_IMAGE_FORMAT_MISMATCH),
87   _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
88   _clS(CL_BUILD_PROGRAM_FAILURE),
89   _clS(CL_MAP_FAILURE),
90   _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
91   _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
92   _clS(CL_COMPILE_PROGRAM_FAILURE),
93   _clS(CL_LINKER_NOT_AVAILABLE),
94   _clS(CL_LINK_PROGRAM_FAILURE),
95   _clS(CL_DEVICE_PARTITION_FAILED),
96   _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
97   _clS(CL_INVALID_VALUE),
98   _clS(CL_INVALID_DEVICE_TYPE),
99   _clS(CL_INVALID_PLATFORM),
100   _clS(CL_INVALID_DEVICE),
101   _clS(CL_INVALID_CONTEXT),
102   _clS(CL_INVALID_QUEUE_PROPERTIES),
103   _clS(CL_INVALID_COMMAND_QUEUE),
104   _clS(CL_INVALID_HOST_PTR),
105   _clS(CL_INVALID_MEM_OBJECT),
106   _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
107   _clS(CL_INVALID_IMAGE_SIZE),
108   _clS(CL_INVALID_SAMPLER),
109   _clS(CL_INVALID_BINARY),
110   _clS(CL_INVALID_BUILD_OPTIONS),
111   _clS(CL_INVALID_PROGRAM),
112   _clS(CL_INVALID_PROGRAM_EXECUTABLE),
113   _clS(CL_INVALID_KERNEL_NAME),
114   _clS(CL_INVALID_KERNEL_DEFINITION),
115   _clS(CL_INVALID_KERNEL),
116   _clS(CL_INVALID_ARG_INDEX),
117   _clS(CL_INVALID_ARG_VALUE),
118   _clS(CL_INVALID_ARG_SIZE),
119   _clS(CL_INVALID_KERNEL_ARGS),
120   _clS(CL_INVALID_WORK_DIMENSION),
121   _clS(CL_INVALID_WORK_GROUP_SIZE),
122   _clS(CL_INVALID_WORK_ITEM_SIZE),
123   _clS(CL_INVALID_GLOBAL_OFFSET),
124   _clS(CL_INVALID_EVENT_WAIT_LIST),
125   _clS(CL_INVALID_EVENT),
126   _clS(CL_INVALID_OPERATION),
127   _clS(CL_INVALID_GL_OBJECT),
128   _clS(CL_INVALID_BUFFER_SIZE),
129   _clS(CL_INVALID_MIP_LEVEL),
130   _clS(CL_INVALID_GLOBAL_WORK_SIZE),
131   _clS(CL_INVALID_PROPERTY),
132   _clS(CL_INVALID_IMAGE_DESCRIPTOR),
133   _clS(CL_INVALID_COMPILER_OPTIONS),
134   _clS(CL_INVALID_LINKER_OPTIONS),
135   _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
136 };
137 #undef _clS
138 #endif
139
140 static char* _clerror2string (cl_int error) __attribute__((unused));
141 static char* _clerror2string (cl_int error) {
142 #if DEBUG_OCL_ICD
143   if (-error > MAX_CL_ERRORS || error > 0) {
144     debug(D_WARN, "Unknown error code %d", error);
145     RETURN_STR("OpenCL Error");
146   }
147   const char *ret=clErrorStr[-error];
148   if (ret == NULL) {
149     debug(D_WARN, "Unknown error code %d", error);
150     RETURN_STR("OpenCL Error");
151   }
152   RETURN_STR(ret);
153 #else
154   static char number[15];
155   if (error==0) {
156     RETURN_STR("CL_SUCCESS");
157   }
158   snprintf(number, 15, "%i", error);
159   RETURN_STR(number);
160 #endif
161 }
162
163 static inline cl_uint _find_num_icds(DIR *dir) {
164   cl_uint num_icds = 0;
165   struct dirent *ent;
166   while( (ent=readdir(dir)) != NULL ){
167     cl_uint d_name_len = strlen(ent->d_name);
168     if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
169       continue;
170     num_icds++;
171   }
172   rewinddir(dir);
173   RETURN(num_icds);
174 }
175
176 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
177   cl_uint num_icds = 0;
178   struct dirent *ent;
179   while( (ent=readdir(dir)) != NULL ){
180     cl_uint d_name_len = strlen(ent->d_name);
181     if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
182       continue;
183     char * lib_path;
184     char * err;
185     unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
186     lib_path = malloc(lib_path_length*sizeof(char));
187     sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
188     debug(D_LOG, "Considering file '%s'", lib_path);
189     FILE *f = fopen(lib_path,"r");
190     free(lib_path);
191
192     fseek(f, 0, SEEK_END);
193     lib_path_length = ftell(f)+1;
194     fseek(f, 0, SEEK_SET);
195     if(lib_path_length == 1) {
196       debug(D_WARN, "File contents too short, skipping ICD");
197       fclose(f);
198       continue;
199     }
200     lib_path = malloc(lib_path_length*sizeof(char));
201     err = fgets(lib_path, lib_path_length, f);
202     fclose(f);
203     if( err == NULL ) {
204       free(lib_path);
205       debug(D_WARN, "Error while loading file contents, skipping ICD");
206       continue;
207     }
208
209     lib_path_length = strlen(lib_path);
210     
211     if( lib_path[lib_path_length-1] == '\n' )
212       lib_path[lib_path_length-1] = '\0';
213
214     debug(D_LOG, "Loading ICD '%s'", lib_path);
215
216     _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
217     if(_icds[num_icds].dl_handle != NULL) {
218       debug(D_LOG, "ICD[%i] loaded", num_icds);
219       num_icds++;
220     } else {
221       debug(D_WARN, "error while dlopening the IDL, skipping ICD");
222     }
223     free(lib_path);
224   }
225   RETURN(num_icds);
226 }
227
228 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
229   void *addr1;
230   debug(D_LOG,"Looking for function %s",name);
231   addr1=dlsym(dlh, name);
232   if (addr1 == NULL) {
233     debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
234   }
235   void* addr2=NULL;
236   if (fn) {
237     addr2=(*fn)(name);
238     if (addr2 == NULL) {
239       debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
240     }
241 #if DEBUG_OCL_ICD
242     if (addr1 && addr2 && addr1!=addr2) {
243       debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
244     }
245 #endif
246   }
247   if (!addr2) addr2=addr1;
248   RETURN(addr2);
249 }
250
251 static int _allocate_platforms(int req) {
252   static cl_uint allocated=0;
253   debug(D_LOG,"Requesting allocation for %d platforms",req);
254   if (allocated - _num_picds < req) {
255     if (allocated==0) {
256       _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
257     } else {
258       req = req - (allocated - _num_picds);
259       _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
260     }
261     allocated += req;
262   }
263   RETURN(allocated - _num_picds);
264 }
265
266 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
267                  cl_platform_id pid, cl_platform_info cname, char* sname) {
268   cl_int error;
269   size_t param_value_size_ret;
270   error = plt_info_ptr(pid, cname, 0, NULL, &param_value_size_ret);
271   if (error != CL_SUCCESS) {
272     debug(D_WARN, "Error %s while requesting %s in platform %p",
273           _clerror2string(error), sname, pid);
274     return NULL;
275   }
276   char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
277   if (param_value == NULL) {
278     debug(D_WARN, "Error in malloc while requesting %s in platform %p",
279           sname, pid);
280     return NULL;
281   }
282   error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
283   if (error != CL_SUCCESS){
284     free(param_value);
285     debug(D_WARN, "Error %s while requesting %s in platform %p",
286           _clerror2string(error), sname, pid);
287     return NULL;
288   }
289   RETURN_STR(param_value);
290 }
291
292 static inline void _find_and_check_platforms(cl_uint num_icds) {
293   cl_uint i;
294   _num_icds = 0;
295   for( i=0; i<num_icds; i++){
296     debug(D_LOG, "Checking ICD %i", i);
297     struct vendor_icd *picd = &_icds[_num_icds];
298     void* dlh = _icds[i].dl_handle;
299     picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
300     clIcdGetPlatformIDsKHR_fn plt_fn_ptr = 
301       _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
302     clGetPlatformInfo_fn plt_info_ptr = 
303       _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
304     if( picd->ext_fn_ptr == NULL
305         || plt_fn_ptr == NULL
306         || plt_info_ptr == NULL) {
307       debug(D_WARN, "Missing symbols in ICD, skipping it");
308       continue;
309     }
310     cl_uint num_platforms=0;
311     cl_int error;
312     error = (*plt_fn_ptr)(0, NULL, &num_platforms);
313     if( error != CL_SUCCESS || num_platforms == 0) {
314       debug(D_LOG, "No platform in ICD, skipping it");
315       continue;
316     }
317     cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
318     error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
319     if( error != CL_SUCCESS ){
320       free(platforms);
321       debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
322       continue;
323     }
324     cl_uint num_valid_platforms=0;
325     cl_uint j;
326     debug(D_LOG, "Try to load %d plateforms", num_platforms);
327     if (_allocate_platforms(num_platforms) < num_platforms) {
328       free(platforms);
329       debug(D_WARN, "Not enought platform allocated. Skipping ICD");
330       continue;
331     }
332     for(j=0; j<num_platforms; j++) {
333       debug(D_LOG, "Checking platform %i", j);
334       struct platform_icd *p=&_picds[_num_picds];
335       p->extension_suffix=NULL;
336       p->vicd=&_icds[i];
337       p->pid=platforms[j];
338 #if DEBUG_OCL_ICD
339       if (debug_ocl_icd_mask & D_DUMP) {
340         dump_platform(p->vicd->ext_fn_ptr, p->pid);
341       }
342 #endif
343       char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
344       if (param_value == NULL){
345         debug(D_WARN, "Skipping platform %i", j);
346         continue;
347       }
348       debug(D_DUMP, "Supported extensions: %s", param_value);
349       if( strstr(param_value, "cl_khr_icd") == NULL){
350         free(param_value);
351         debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
352         continue;
353       }
354       free(param_value);
355       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
356       if (param_value == NULL){
357         debug(D_WARN, "Skipping platform %i", j);
358         continue;
359       }
360       p->extension_suffix = param_value;
361       debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
362 #if DEBUG_OCL_ICD
363       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
364       if (param_value != NULL){
365         debug(D_DUMP, "Profile: %s", param_value);
366         free(param_value);
367       }
368 #endif
369       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
370       p->version = param_value;
371       if (param_value != NULL){
372         debug(D_DUMP, "Version: %s", param_value);
373         free(param_value);
374       }
375 #if DEBUG_OCL_ICD
376       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
377       if (param_value != NULL){
378         debug(D_DUMP, "Name: %s", param_value);
379         free(param_value);
380       }
381       param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
382       if (param_value != NULL){
383         debug(D_DUMP, "Vendor: %s", param_value);
384         free(param_value);
385       }
386 #endif
387       num_valid_platforms++;
388       _num_picds++;
389     }
390     if( num_valid_platforms != 0 ) {
391       if ( _num_icds != i ) {
392         picd->dl_handle = dlh;
393       }
394       _num_icds++;
395       picd->num_platforms = num_valid_platforms;
396       _icds[i].first_platform = _num_picds - num_valid_platforms;
397     } else {
398       dlclose(dlh);
399     }
400     free(platforms);
401   }
402 }
403
404 static void _initClIcd( void ) {
405   if( _initialized )
406     return;
407   debug_init();
408   cl_uint num_icds = 0;
409   DIR *dir;
410   const char* dir_path=getenv("OCL_ICD_VENDORS");
411   if (! dir_path || dir_path[0]==0) {
412     debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
413     dir_path=ETC_OPENCL_VENDORS;
414   }
415   debug(D_LOG,"Reading icd list from '%s'", dir_path);
416   dir = opendir(dir_path);
417   if(dir == NULL) {
418     goto abort;
419   }
420
421   num_icds = _find_num_icds(dir);
422   if(num_icds == 0) {
423     goto abort;
424   }
425
426   _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
427   if (_icds == NULL) {
428     goto abort;
429   }
430   
431   num_icds = _open_drivers(dir, dir_path);
432   if(num_icds == 0) {
433     goto abort;
434   }
435
436   _find_and_check_platforms(num_icds);
437   if(_num_icds == 0){
438     goto abort;
439   }
440
441   if (_num_icds < num_icds) {
442     _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
443   }
444   debug(D_WARN, "%d valid vendor(s)!", _num_icds);
445   _initialized = 1;
446   return;
447 abort:
448   _num_icds = 0;
449   _initialized = 1;
450   if (_icds) {
451     free(_icds);
452     _icds = NULL;
453   }
454   return;
455 }
456
457 #pragma GCC visibility pop
458 #define hidden_alias(name) \
459   typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
460
461 CL_API_ENTRY void * CL_API_CALL
462 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
463   debug_trace();
464   if( !_initialized )
465     _initClIcd();
466   if( func_name == NULL )
467     return NULL;
468   cl_uint suffix_length;
469   cl_uint i;
470   void * return_value=NULL;
471   struct func_desc const * fn=&function_description[0];
472   while (fn->name != NULL) {
473     if (strcmp(func_name, fn->name)==0)
474       RETURN(fn->addr);
475     fn++;
476   }
477   for(i=0; i<_num_picds; i++) {
478     suffix_length = strlen(_picds[i].extension_suffix);
479     if( suffix_length > strlen(func_name) )
480       continue;
481     if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
482       RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
483   }
484   RETURN(return_value);
485 }
486 hidden_alias(clGetExtensionFunctionAddress);
487
488 CL_API_ENTRY cl_int CL_API_CALL
489 clGetPlatformIDs(cl_uint          num_entries,
490                  cl_platform_id * platforms,
491                  cl_uint *        num_platforms) CL_API_SUFFIX__VERSION_1_0 {
492   debug_trace();
493   if( !_initialized )
494     _initClIcd();
495   if( platforms == NULL && num_platforms == NULL )
496     RETURN(CL_INVALID_VALUE);
497   if( num_entries == 0 && platforms != NULL )
498     RETURN(CL_INVALID_VALUE);
499   if( _num_icds == 0)
500     RETURN(CL_PLATFORM_NOT_FOUND_KHR);
501
502   cl_uint i;
503   if( num_platforms != NULL ){
504     *num_platforms = _num_picds;
505   }
506   if( platforms != NULL ) {
507     cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
508     for( i=0; i<n_platforms; i++) {
509       *(platforms++) = _picds[i].pid;
510     }
511   }
512   return CL_SUCCESS;
513 }
514 hidden_alias(clGetPlatformIDs);
515
516 CL_API_ENTRY cl_context CL_API_CALL
517 clCreateContext(const cl_context_properties *  properties ,
518                 cl_uint                        num_devices ,
519                 const cl_device_id *           devices ,
520                 void (CL_CALLBACK *  pfn_notify )(const char *, const void *, size_t, void *),
521                 void *                         user_data ,
522                 cl_int *                       errcode_ret ){
523   debug_trace();
524   if( !_initialized )
525     _initClIcd();
526   cl_uint i=0;
527   if( properties != NULL){
528     while( properties[i] != 0 ) {
529       if( properties[i] == CL_CONTEXT_PLATFORM )
530         RETURN(((struct _cl_platform_id *) properties[i+1])
531           ->dispatch->clCreateContext(properties, num_devices, devices,
532                         pfn_notify, user_data, errcode_ret));
533       i += 2;
534     }
535   }
536   if(devices == NULL || num_devices == 0) {
537     if(errcode_ret) {
538       *errcode_ret = CL_INVALID_VALUE;
539     }
540     RETURN(NULL);
541   }
542   RETURN(((struct _cl_device_id *)devices[0])
543     ->dispatch->clCreateContext(properties, num_devices, devices,
544                   pfn_notify, user_data, errcode_ret));
545 }
546 hidden_alias(clCreateContext);
547
548 CL_API_ENTRY cl_context CL_API_CALL
549 clCreateContextFromType(const cl_context_properties *  properties ,
550                         cl_device_type                 device_type ,
551                         void (CL_CALLBACK *      pfn_notify )(const char *, const void *, size_t, void *),
552                         void *                         user_data ,
553                         cl_int *                       errcode_ret ){
554   debug_trace();
555   if( !_initialized )
556     _initClIcd();
557   cl_uint i=0;
558   if( properties != NULL){
559     while( properties[i] != 0 ) {
560       if( properties[i] == CL_CONTEXT_PLATFORM )
561         if (properties[i+1] == 0) {
562           goto out;
563         }
564         return ((struct _cl_platform_id *) properties[i+1])
565           ->dispatch->clCreateContextFromType(properties, device_type,
566                         pfn_notify, user_data, errcode_ret);
567       i += 2;
568     }
569   } else {
570     /* if properties is null, the selected platform is implementation dependant
571      * We will use the first one if any
572      */
573     if(_num_picds == 0) {
574       if(errcode_ret) {
575         *errcode_ret = CL_INVALID_VALUE;
576       }
577       RETURN(NULL);
578     }
579     RETURN(_picds[0].pid->dispatch->clCreateContextFromType
580         (properties, device_type, pfn_notify, user_data, errcode_ret));
581   }
582  out:
583   if(errcode_ret) {
584     *errcode_ret = CL_INVALID_PLATFORM;
585   }
586   RETURN(NULL);
587 }
588 hidden_alias(clCreateContextFromType);
589
590 CL_API_ENTRY cl_int CL_API_CALL
591 clGetGLContextInfoKHR(const cl_context_properties *  properties ,
592                       cl_gl_context_info             param_name ,
593                       size_t                         param_value_size ,
594                       void *                         param_value ,
595                       size_t *                       param_value_size_ret ){
596   debug_trace();
597   if( !_initialized )
598     _initClIcd();
599   cl_uint i=0;
600   if( properties != NULL){
601     while( properties[i] != 0 ) {
602       if( properties[i] == CL_CONTEXT_PLATFORM )
603         RETURN(((struct _cl_platform_id *) properties[i+1])
604           ->dispatch->clGetGLContextInfoKHR(properties, param_name,
605                         param_value_size, param_value, param_value_size_ret));
606       i += 2;
607     }
608   }
609   RETURN(CL_INVALID_PLATFORM);
610 }
611 hidden_alias(clGetGLContextInfoKHR);
612
613 CL_API_ENTRY cl_int CL_API_CALL
614 clWaitForEvents(cl_uint              num_events ,
615                 const cl_event *     event_list ){
616   debug_trace();
617   if( num_events == 0 || event_list == NULL )
618     RETURN(CL_INVALID_VALUE);
619   RETURN(((struct _cl_event *)event_list[0])
620     ->dispatch->clWaitForEvents(num_events, event_list));
621 }
622 hidden_alias(clWaitForEvents);
623
624 CL_API_ENTRY cl_int CL_API_CALL
625 clUnloadCompiler( void ){
626   debug_trace();
627   RETURN(CL_SUCCESS);
628 }
629 hidden_alias(clUnloadCompiler);