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 #include <sys/types.h>
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
46 #pragma GCC visibility push(hidden)
48 #include "ocl_icd_loader.h"
49 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
50 #include "ocl_icd_debug.h"
52 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
54 int debug_ocl_icd_mask=0;
56 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
57 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
61 cl_uint num_platforms;
62 cl_uint first_platform;
64 clGetExtensionFunctionAddress_fn ext_fn_ptr;
68 char * extension_suffix;
70 struct vendor_icd *vicd;
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;
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] = {
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),
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)
146 static char* _clerror2string (cl_int error) __attribute__((unused));
147 static char* _clerror2string (cl_int error) {
149 if (-error > MAX_CL_ERRORS || error > 0) {
150 debug(D_WARN, "Unknown error code %d", error);
151 RETURN_STR("OpenCL Error");
153 const char *ret=clErrorStr[-error];
155 debug(D_WARN, "Unknown error code %d", error);
156 RETURN_STR("OpenCL Error");
160 static char number[15];
162 RETURN_STR("CL_SUCCESS");
164 snprintf(number, 15, "%i", error);
169 static inline cl_uint _find_num_icds(DIR *dir) {
170 cl_uint num_icds = 0;
172 while( (ent=readdir(dir)) != NULL ){
173 cl_uint d_name_len = strlen(ent->d_name);
174 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
182 static inline cl_uint _load_icd(int num_icds, const char* lib_path) {
184 debug(D_LOG, "Loading ICD '%s'", lib_path);
186 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
187 if(_icds[num_icds].dl_handle != NULL) {
188 debug(D_LOG, "ICD[%i] loaded", num_icds);
191 debug(D_WARN, "error while dlopening the IDL: '%s',\n => skipping ICD", dlerror());
196 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
197 cl_uint num_icds = 0;
199 while( (ent=readdir(dir)) != NULL ){
200 cl_uint d_name_len = strlen(ent->d_name);
201 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
205 unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
206 lib_path = malloc(lib_path_length*sizeof(char));
207 sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
208 debug(D_LOG, "Considering file '%s'", lib_path);
209 FILE *f = fopen(lib_path,"r");
212 fseek(f, 0, SEEK_END);
213 lib_path_length = ftell(f)+1;
214 fseek(f, 0, SEEK_SET);
215 if(lib_path_length == 1) {
216 debug(D_WARN, "File contents too short, skipping ICD");
220 lib_path = malloc(lib_path_length*sizeof(char));
221 err = fgets(lib_path, lib_path_length, f);
225 debug(D_WARN, "Error while loading file contents, skipping ICD");
229 lib_path_length = strlen(lib_path);
231 if( lib_path[lib_path_length-1] == '\n' )
232 lib_path[lib_path_length-1] = '\0';
234 num_icds += _load_icd(num_icds, lib_path);
241 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
243 debug(D_LOG,"Looking for function %s",name);
244 addr1=dlsym(dlh, name);
246 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
252 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
255 if (addr1 && addr2 && addr1!=addr2) {
256 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
260 if (!addr2) addr2=addr1;
264 static int _allocate_platforms(int req) {
265 static cl_uint allocated=0;
266 debug(D_LOG,"Requesting allocation for %d platforms",req);
267 if (allocated - _num_picds < req) {
269 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
271 req = req - (allocated - _num_picds);
272 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
276 RETURN(allocated - _num_picds);
279 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
280 cl_platform_id pid, cl_platform_info cname, char* sname) {
282 size_t param_value_size_ret;
283 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
284 if (error != CL_SUCCESS) {
285 debug(D_WARN, "Error %s while requesting %s in platform %p",
286 _clerror2string(error), sname, pid);
289 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
290 if (param_value == NULL) {
291 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
295 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
296 if (error != CL_SUCCESS){
298 debug(D_WARN, "Error %s while requesting %s in platform %p",
299 _clerror2string(error), sname, pid);
302 RETURN_STR(param_value);
305 static inline void _find_and_check_platforms(cl_uint num_icds) {
308 for( i=0; i<num_icds; i++){
309 debug(D_LOG, "Checking ICD %i", i);
310 struct vendor_icd *picd = &_icds[_num_icds];
311 void* dlh = _icds[i].dl_handle;
312 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
313 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
314 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
315 clGetPlatformInfo_fn plt_info_ptr =
316 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
317 if( picd->ext_fn_ptr == NULL
318 || plt_fn_ptr == NULL
319 || plt_info_ptr == NULL) {
320 debug(D_WARN, "Missing symbols in ICD, skipping it");
323 cl_uint num_platforms=0;
325 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
326 if( error != CL_SUCCESS || num_platforms == 0) {
327 debug(D_LOG, "No platform in ICD, skipping it");
330 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
331 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
332 if( error != CL_SUCCESS ){
334 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
337 cl_uint num_valid_platforms=0;
339 debug(D_LOG, "Try to load %d plateforms", num_platforms);
340 if (_allocate_platforms(num_platforms) < num_platforms) {
342 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
345 for(j=0; j<num_platforms; j++) {
346 debug(D_LOG, "Checking platform %i", j);
347 struct platform_icd *p=&_picds[_num_picds];
348 p->extension_suffix=NULL;
352 if (debug_ocl_icd_mask & D_DUMP) {
353 int log=debug_ocl_icd_mask & D_TRACE;
354 debug_ocl_icd_mask &= ~D_TRACE;
355 dump_platform(p->vicd->ext_fn_ptr, p->pid);
356 debug_ocl_icd_mask |= log;
359 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
360 if (param_value == NULL){
361 debug(D_WARN, "Skipping platform %i", j);
364 debug(D_DUMP, "Supported extensions: %s", param_value);
365 if( strstr(param_value, "cl_khr_icd") == NULL){
367 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
371 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
372 if (param_value == NULL){
373 debug(D_WARN, "Skipping platform %i", j);
376 p->extension_suffix = param_value;
377 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
379 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
380 if (param_value != NULL){
381 debug(D_DUMP, "Profile: %s", param_value);
385 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
386 p->version = param_value;
387 if (param_value != NULL){
388 debug(D_DUMP, "Version: %s", param_value);
392 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
393 if (param_value != NULL){
394 debug(D_DUMP, "Name: %s", param_value);
397 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
398 if (param_value != NULL){
399 debug(D_DUMP, "Vendor: %s", param_value);
403 num_valid_platforms++;
406 if( num_valid_platforms != 0 ) {
407 if ( _num_icds != i ) {
408 picd->dl_handle = dlh;
411 picd->num_platforms = num_valid_platforms;
412 _icds[i].first_platform = _num_picds - num_valid_platforms;
420 static void __initClIcd( void ) {
422 cl_uint num_icds = 0;
425 const char* dir_path=getenv("OCL_ICD_VENDORS");
426 if (! dir_path || dir_path[0]==0) {
427 debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
428 dir_path=ETC_OPENCL_VENDORS;
433 int ret=stat(dir_path, &buf);
434 if (ret != 0 && errno != ENOENT) {
435 debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
437 if (ret == 0 && S_ISDIR(buf.st_mode)) {
443 debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
447 debug(D_LOG,"Reading icd list from '%s'", dir_path);
448 dir = opendir(dir_path);
450 if (errno == ENOTDIR) {
451 debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
457 num_icds = _find_num_icds(dir);
463 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
469 num_icds = _load_icd(0, dir_path);
471 num_icds = _open_drivers(dir, dir_path);
477 _find_and_check_platforms(num_icds);
482 if (_num_icds < num_icds) {
483 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
485 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
497 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
501 volatile static __thread int in_init = 0;
502 volatile static cl_uint _initialized = 0;
504 static inline void __attribute__((constructor)) _initClIcd( void ) {
509 /* probably reentrency */
512 __sync_synchronize();
513 pthread_once(&once_init, &__initClIcd);
514 __sync_synchronize();
518 if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
520 __sync_synchronize();
522 __sync_synchronize();
526 /* probably reentrency (could also be user threads). */
528 /* someone else started __initClIcd(). We wait until its end. */
529 debug(D_WARN, "Waiting end of init");
530 while (!_initialized) ;
531 debug(D_WARN, "Wait done");
538 #pragma GCC visibility pop
539 #define hidden_alias(name) \
540 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
542 CL_API_ENTRY void * CL_API_CALL
543 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
546 if( func_name == NULL )
548 cl_uint suffix_length;
550 void * return_value=NULL;
551 struct func_desc const * fn=&function_description[0];
552 while (fn->name != NULL) {
553 if (strcmp(func_name, fn->name)==0)
557 for(i=0; i<_num_picds; i++) {
558 suffix_length = strlen(_picds[i].extension_suffix);
559 if( suffix_length > strlen(func_name) )
561 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
562 RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
564 RETURN(return_value);
566 hidden_alias(clGetExtensionFunctionAddress);
568 CL_API_ENTRY cl_int CL_API_CALL
569 clGetPlatformIDs(cl_uint num_entries,
570 cl_platform_id * platforms,
571 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
574 if( platforms == NULL && num_platforms == NULL )
575 RETURN(CL_INVALID_VALUE);
576 if( num_entries == 0 && platforms != NULL )
577 RETURN(CL_INVALID_VALUE);
579 RETURN(CL_PLATFORM_NOT_FOUND_KHR);
582 if( num_platforms != NULL ){
583 *num_platforms = _num_picds;
585 if( platforms != NULL ) {
586 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
587 for( i=0; i<n_platforms; i++) {
588 *(platforms++) = _picds[i].pid;
593 hidden_alias(clGetPlatformIDs);
595 CL_API_ENTRY cl_context CL_API_CALL
596 clCreateContext(const cl_context_properties * properties ,
597 cl_uint num_devices ,
598 const cl_device_id * devices ,
599 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
601 cl_int * errcode_ret ){
605 if( properties != NULL){
606 while( properties[i] != 0 ) {
607 if( properties[i] == CL_CONTEXT_PLATFORM )
608 RETURN(((struct _cl_platform_id *) properties[i+1])
609 ->dispatch->clCreateContext(properties, num_devices, devices,
610 pfn_notify, user_data, errcode_ret));
614 if(devices == NULL || num_devices == 0) {
616 *errcode_ret = CL_INVALID_VALUE;
620 RETURN(((struct _cl_device_id *)devices[0])
621 ->dispatch->clCreateContext(properties, num_devices, devices,
622 pfn_notify, user_data, errcode_ret));
624 hidden_alias(clCreateContext);
626 CL_API_ENTRY cl_context CL_API_CALL
627 clCreateContextFromType(const cl_context_properties * properties ,
628 cl_device_type device_type ,
629 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
631 cl_int * errcode_ret ){
635 if( properties != NULL){
636 while( properties[i] != 0 ) {
637 if( properties[i] == CL_CONTEXT_PLATFORM )
638 if (properties[i+1] == 0) {
641 return ((struct _cl_platform_id *) properties[i+1])
642 ->dispatch->clCreateContextFromType(properties, device_type,
643 pfn_notify, user_data, errcode_ret);
647 /* if properties is null, the selected platform is implementation dependant
648 * We will use the first one if any
650 if(_num_picds == 0) {
652 *errcode_ret = CL_INVALID_VALUE;
656 RETURN(_picds[0].pid->dispatch->clCreateContextFromType
657 (properties, device_type, pfn_notify, user_data, errcode_ret));
661 *errcode_ret = CL_INVALID_PLATFORM;
665 hidden_alias(clCreateContextFromType);
667 CL_API_ENTRY cl_int CL_API_CALL
668 clGetGLContextInfoKHR(const cl_context_properties * properties ,
669 cl_gl_context_info param_name ,
670 size_t param_value_size ,
672 size_t * param_value_size_ret ){
676 if( properties != NULL){
677 while( properties[i] != 0 ) {
678 if( properties[i] == CL_CONTEXT_PLATFORM )
679 RETURN(((struct _cl_platform_id *) properties[i+1])
680 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
681 param_value_size, param_value, param_value_size_ret));
685 RETURN(CL_INVALID_PLATFORM);
687 hidden_alias(clGetGLContextInfoKHR);
689 CL_API_ENTRY cl_int CL_API_CALL
690 clWaitForEvents(cl_uint num_events ,
691 const cl_event * event_list ){
693 if( num_events == 0 || event_list == NULL )
694 RETURN(CL_INVALID_VALUE);
695 RETURN(((struct _cl_event *)event_list[0])
696 ->dispatch->clWaitForEvents(num_events, event_list));
698 hidden_alias(clWaitForEvents);
700 CL_API_ENTRY cl_int CL_API_CALL
701 clUnloadCompiler( void ){
705 hidden_alias(clUnloadCompiler);