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, skipping ICD");
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 dump_platform(p->vicd->ext_fn_ptr, p->pid);
356 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
357 if (param_value == NULL){
358 debug(D_WARN, "Skipping platform %i", j);
361 debug(D_DUMP, "Supported extensions: %s", param_value);
362 if( strstr(param_value, "cl_khr_icd") == NULL){
364 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
368 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
369 if (param_value == NULL){
370 debug(D_WARN, "Skipping platform %i", j);
373 p->extension_suffix = param_value;
374 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
376 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
377 if (param_value != NULL){
378 debug(D_DUMP, "Profile: %s", param_value);
382 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
383 p->version = param_value;
384 if (param_value != NULL){
385 debug(D_DUMP, "Version: %s", param_value);
389 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
390 if (param_value != NULL){
391 debug(D_DUMP, "Name: %s", param_value);
394 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
395 if (param_value != NULL){
396 debug(D_DUMP, "Vendor: %s", param_value);
400 num_valid_platforms++;
403 if( num_valid_platforms != 0 ) {
404 if ( _num_icds != i ) {
405 picd->dl_handle = dlh;
408 picd->num_platforms = num_valid_platforms;
409 _icds[i].first_platform = _num_picds - num_valid_platforms;
417 static void __initClIcd( void ) {
419 cl_uint num_icds = 0;
422 const char* dir_path=getenv("OCL_ICD_VENDORS");
423 if (! dir_path || dir_path[0]==0) {
424 debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
425 dir_path=ETC_OPENCL_VENDORS;
430 int ret=stat(dir_path, &buf);
431 if (ret != 0 && errno != ENOENT) {
432 debug(D_WARN, "Cannot stat '%s'. Aborting", dir_path);
434 if (ret == 0 && S_ISDIR(buf.st_mode)) {
440 debug(D_LOG,"Only loading '%s' as an ICD", dir_path);
444 debug(D_LOG,"Reading icd list from '%s'", dir_path);
445 dir = opendir(dir_path);
447 if (errno == ENOTDIR) {
448 debug(D_DUMP, "%s is not a directory, trying to use it as a ICD libname",
454 num_icds = _find_num_icds(dir);
460 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
466 num_icds = _load_icd(0, dir_path);
468 num_icds = _open_drivers(dir, dir_path);
474 _find_and_check_platforms(num_icds);
479 if (_num_icds < num_icds) {
480 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
482 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
494 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
498 volatile static cl_uint _initialized = 0;
500 static inline void __attribute__((constructor)) _initClIcd( void ) {
504 pthread_once(&once_init, &__initClIcd);
506 if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
509 /* someone else started __initClIcd(). We wait until its end. */
510 while (!_initialized) ;
516 #pragma GCC visibility pop
517 #define hidden_alias(name) \
518 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
520 CL_API_ENTRY void * CL_API_CALL
521 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
524 if( func_name == NULL )
526 cl_uint suffix_length;
528 void * return_value=NULL;
529 struct func_desc const * fn=&function_description[0];
530 while (fn->name != NULL) {
531 if (strcmp(func_name, fn->name)==0)
535 for(i=0; i<_num_picds; i++) {
536 suffix_length = strlen(_picds[i].extension_suffix);
537 if( suffix_length > strlen(func_name) )
539 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
540 RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
542 RETURN(return_value);
544 hidden_alias(clGetExtensionFunctionAddress);
546 CL_API_ENTRY cl_int CL_API_CALL
547 clGetPlatformIDs(cl_uint num_entries,
548 cl_platform_id * platforms,
549 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
552 if( platforms == NULL && num_platforms == NULL )
553 RETURN(CL_INVALID_VALUE);
554 if( num_entries == 0 && platforms != NULL )
555 RETURN(CL_INVALID_VALUE);
557 RETURN(CL_PLATFORM_NOT_FOUND_KHR);
560 if( num_platforms != NULL ){
561 *num_platforms = _num_picds;
563 if( platforms != NULL ) {
564 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
565 for( i=0; i<n_platforms; i++) {
566 *(platforms++) = _picds[i].pid;
571 hidden_alias(clGetPlatformIDs);
573 CL_API_ENTRY cl_context CL_API_CALL
574 clCreateContext(const cl_context_properties * properties ,
575 cl_uint num_devices ,
576 const cl_device_id * devices ,
577 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
579 cl_int * errcode_ret ){
583 if( properties != NULL){
584 while( properties[i] != 0 ) {
585 if( properties[i] == CL_CONTEXT_PLATFORM )
586 RETURN(((struct _cl_platform_id *) properties[i+1])
587 ->dispatch->clCreateContext(properties, num_devices, devices,
588 pfn_notify, user_data, errcode_ret));
592 if(devices == NULL || num_devices == 0) {
594 *errcode_ret = CL_INVALID_VALUE;
598 RETURN(((struct _cl_device_id *)devices[0])
599 ->dispatch->clCreateContext(properties, num_devices, devices,
600 pfn_notify, user_data, errcode_ret));
602 hidden_alias(clCreateContext);
604 CL_API_ENTRY cl_context CL_API_CALL
605 clCreateContextFromType(const cl_context_properties * properties ,
606 cl_device_type device_type ,
607 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
609 cl_int * errcode_ret ){
613 if( properties != NULL){
614 while( properties[i] != 0 ) {
615 if( properties[i] == CL_CONTEXT_PLATFORM )
616 if (properties[i+1] == 0) {
619 return ((struct _cl_platform_id *) properties[i+1])
620 ->dispatch->clCreateContextFromType(properties, device_type,
621 pfn_notify, user_data, errcode_ret);
625 /* if properties is null, the selected platform is implementation dependant
626 * We will use the first one if any
628 if(_num_picds == 0) {
630 *errcode_ret = CL_INVALID_VALUE;
634 RETURN(_picds[0].pid->dispatch->clCreateContextFromType
635 (properties, device_type, pfn_notify, user_data, errcode_ret));
639 *errcode_ret = CL_INVALID_PLATFORM;
643 hidden_alias(clCreateContextFromType);
645 CL_API_ENTRY cl_int CL_API_CALL
646 clGetGLContextInfoKHR(const cl_context_properties * properties ,
647 cl_gl_context_info param_name ,
648 size_t param_value_size ,
650 size_t * param_value_size_ret ){
654 if( properties != NULL){
655 while( properties[i] != 0 ) {
656 if( properties[i] == CL_CONTEXT_PLATFORM )
657 RETURN(((struct _cl_platform_id *) properties[i+1])
658 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
659 param_value_size, param_value, param_value_size_ret));
663 RETURN(CL_INVALID_PLATFORM);
665 hidden_alias(clGetGLContextInfoKHR);
667 CL_API_ENTRY cl_int CL_API_CALL
668 clWaitForEvents(cl_uint num_events ,
669 const cl_event * event_list ){
671 if( num_events == 0 || event_list == NULL )
672 RETURN(CL_INVALID_VALUE);
673 RETURN(((struct _cl_event *)event_list[0])
674 ->dispatch->clWaitForEvents(num_events, event_list));
676 hidden_alias(clWaitForEvents);
678 CL_API_ENTRY cl_int CL_API_CALL
679 clUnloadCompiler( void ){
683 hidden_alias(clUnloadCompiler);