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.
36 #pragma GCC diagnostic push
37 # pragma GCC diagnostic ignored "-Wcpp"
38 # define CL_USE_DEPRECATED_OPENCL_1_1_APIS
39 # include <CL/opencl.h>
40 #pragma GCC diagnostic pop
42 #pragma GCC visibility push(hidden)
44 #include "ocl_icd_loader.h"
45 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
46 #include "ocl_icd_debug.h"
48 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
50 int debug_ocl_icd_mask=0;
52 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
53 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
57 cl_uint num_platforms;
58 cl_uint first_platform;
60 clGetExtensionFunctionAddress_fn ext_fn_ptr;
64 char * extension_suffix;
66 struct vendor_icd *vicd;
70 struct vendor_icd *_icds=NULL;
71 struct platform_icd *_picds=NULL;
72 static cl_uint _num_icds = 0;
73 static cl_uint _num_picds = 0;
76 # define _clS(x) [-x] = #x
77 # define MAX_CL_ERRORS CL_INVALID_DEVICE_PARTITION_COUNT
78 static char const * const clErrorStr[-MAX_CL_ERRORS+1] = {
80 _clS(CL_DEVICE_NOT_FOUND),
81 _clS(CL_DEVICE_NOT_AVAILABLE),
82 _clS(CL_COMPILER_NOT_AVAILABLE),
83 _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
84 _clS(CL_OUT_OF_RESOURCES),
85 _clS(CL_OUT_OF_HOST_MEMORY),
86 _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
87 _clS(CL_MEM_COPY_OVERLAP),
88 _clS(CL_IMAGE_FORMAT_MISMATCH),
89 _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
90 _clS(CL_BUILD_PROGRAM_FAILURE),
92 _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
93 _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
94 _clS(CL_COMPILE_PROGRAM_FAILURE),
95 _clS(CL_LINKER_NOT_AVAILABLE),
96 _clS(CL_LINK_PROGRAM_FAILURE),
97 _clS(CL_DEVICE_PARTITION_FAILED),
98 _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
99 _clS(CL_INVALID_VALUE),
100 _clS(CL_INVALID_DEVICE_TYPE),
101 _clS(CL_INVALID_PLATFORM),
102 _clS(CL_INVALID_DEVICE),
103 _clS(CL_INVALID_CONTEXT),
104 _clS(CL_INVALID_QUEUE_PROPERTIES),
105 _clS(CL_INVALID_COMMAND_QUEUE),
106 _clS(CL_INVALID_HOST_PTR),
107 _clS(CL_INVALID_MEM_OBJECT),
108 _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
109 _clS(CL_INVALID_IMAGE_SIZE),
110 _clS(CL_INVALID_SAMPLER),
111 _clS(CL_INVALID_BINARY),
112 _clS(CL_INVALID_BUILD_OPTIONS),
113 _clS(CL_INVALID_PROGRAM),
114 _clS(CL_INVALID_PROGRAM_EXECUTABLE),
115 _clS(CL_INVALID_KERNEL_NAME),
116 _clS(CL_INVALID_KERNEL_DEFINITION),
117 _clS(CL_INVALID_KERNEL),
118 _clS(CL_INVALID_ARG_INDEX),
119 _clS(CL_INVALID_ARG_VALUE),
120 _clS(CL_INVALID_ARG_SIZE),
121 _clS(CL_INVALID_KERNEL_ARGS),
122 _clS(CL_INVALID_WORK_DIMENSION),
123 _clS(CL_INVALID_WORK_GROUP_SIZE),
124 _clS(CL_INVALID_WORK_ITEM_SIZE),
125 _clS(CL_INVALID_GLOBAL_OFFSET),
126 _clS(CL_INVALID_EVENT_WAIT_LIST),
127 _clS(CL_INVALID_EVENT),
128 _clS(CL_INVALID_OPERATION),
129 _clS(CL_INVALID_GL_OBJECT),
130 _clS(CL_INVALID_BUFFER_SIZE),
131 _clS(CL_INVALID_MIP_LEVEL),
132 _clS(CL_INVALID_GLOBAL_WORK_SIZE),
133 _clS(CL_INVALID_PROPERTY),
134 _clS(CL_INVALID_IMAGE_DESCRIPTOR),
135 _clS(CL_INVALID_COMPILER_OPTIONS),
136 _clS(CL_INVALID_LINKER_OPTIONS),
137 _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
142 static char* _clerror2string (cl_int error) __attribute__((unused));
143 static char* _clerror2string (cl_int error) {
145 if (-error > MAX_CL_ERRORS || error > 0) {
146 debug(D_WARN, "Unknown error code %d", error);
147 RETURN_STR("OpenCL Error");
149 const char *ret=clErrorStr[-error];
151 debug(D_WARN, "Unknown error code %d", error);
152 RETURN_STR("OpenCL Error");
156 static char number[15];
158 RETURN_STR("CL_SUCCESS");
160 snprintf(number, 15, "%i", error);
165 static inline cl_uint _find_num_icds(DIR *dir) {
166 cl_uint num_icds = 0;
168 while( (ent=readdir(dir)) != NULL ){
169 cl_uint d_name_len = strlen(ent->d_name);
170 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
178 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
179 cl_uint num_icds = 0;
181 while( (ent=readdir(dir)) != NULL ){
182 cl_uint d_name_len = strlen(ent->d_name);
183 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
187 unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
188 lib_path = malloc(lib_path_length*sizeof(char));
189 sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
190 debug(D_LOG, "Considering file '%s'", lib_path);
191 FILE *f = fopen(lib_path,"r");
194 fseek(f, 0, SEEK_END);
195 lib_path_length = ftell(f)+1;
196 fseek(f, 0, SEEK_SET);
197 if(lib_path_length == 1) {
198 debug(D_WARN, "File contents too short, skipping ICD");
202 lib_path = malloc(lib_path_length*sizeof(char));
203 err = fgets(lib_path, lib_path_length, f);
207 debug(D_WARN, "Error while loading file contents, skipping ICD");
211 lib_path_length = strlen(lib_path);
213 if( lib_path[lib_path_length-1] == '\n' )
214 lib_path[lib_path_length-1] = '\0';
216 debug(D_LOG, "Loading ICD '%s'", lib_path);
218 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
219 if(_icds[num_icds].dl_handle != NULL) {
220 debug(D_LOG, "ICD[%i] loaded", num_icds);
223 debug(D_WARN, "error while dlopening the IDL, skipping ICD");
230 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
232 debug(D_LOG,"Looking for function %s",name);
233 addr1=dlsym(dlh, name);
235 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
241 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
244 if (addr1 && addr2 && addr1!=addr2) {
245 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
249 if (!addr2) addr2=addr1;
253 static int _allocate_platforms(int req) {
254 static cl_uint allocated=0;
255 debug(D_LOG,"Requesting allocation for %d platforms",req);
256 if (allocated - _num_picds < req) {
258 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
260 req = req - (allocated - _num_picds);
261 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
265 RETURN(allocated - _num_picds);
268 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
269 cl_platform_id pid, cl_platform_info cname, char* sname) {
271 size_t param_value_size_ret;
272 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
273 if (error != CL_SUCCESS) {
274 debug(D_WARN, "Error %s while requesting %s in platform %p",
275 _clerror2string(error), sname, pid);
278 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
279 if (param_value == NULL) {
280 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
284 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
285 if (error != CL_SUCCESS){
287 debug(D_WARN, "Error %s while requesting %s in platform %p",
288 _clerror2string(error), sname, pid);
291 RETURN_STR(param_value);
294 static inline void _find_and_check_platforms(cl_uint num_icds) {
297 for( i=0; i<num_icds; i++){
298 debug(D_LOG, "Checking ICD %i", i);
299 struct vendor_icd *picd = &_icds[_num_icds];
300 void* dlh = _icds[i].dl_handle;
301 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
302 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
303 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
304 clGetPlatformInfo_fn plt_info_ptr =
305 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
306 if( picd->ext_fn_ptr == NULL
307 || plt_fn_ptr == NULL
308 || plt_info_ptr == NULL) {
309 debug(D_WARN, "Missing symbols in ICD, skipping it");
312 cl_uint num_platforms=0;
314 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
315 if( error != CL_SUCCESS || num_platforms == 0) {
316 debug(D_LOG, "No platform in ICD, skipping it");
319 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
320 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
321 if( error != CL_SUCCESS ){
323 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
326 cl_uint num_valid_platforms=0;
328 debug(D_LOG, "Try to load %d plateforms", num_platforms);
329 if (_allocate_platforms(num_platforms) < num_platforms) {
331 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
334 for(j=0; j<num_platforms; j++) {
335 debug(D_LOG, "Checking platform %i", j);
336 struct platform_icd *p=&_picds[_num_picds];
337 p->extension_suffix=NULL;
341 if (debug_ocl_icd_mask & D_DUMP) {
342 dump_platform(p->vicd->ext_fn_ptr, p->pid);
345 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
346 if (param_value == NULL){
347 debug(D_WARN, "Skipping platform %i", j);
350 debug(D_DUMP, "Supported extensions: %s", param_value);
351 if( strstr(param_value, "cl_khr_icd") == NULL){
353 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
357 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
358 if (param_value == NULL){
359 debug(D_WARN, "Skipping platform %i", j);
362 p->extension_suffix = param_value;
363 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
365 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
366 if (param_value != NULL){
367 debug(D_DUMP, "Profile: %s", param_value);
371 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
372 p->version = param_value;
373 if (param_value != NULL){
374 debug(D_DUMP, "Version: %s", param_value);
378 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
379 if (param_value != NULL){
380 debug(D_DUMP, "Name: %s", param_value);
383 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
384 if (param_value != NULL){
385 debug(D_DUMP, "Vendor: %s", param_value);
389 num_valid_platforms++;
392 if( num_valid_platforms != 0 ) {
393 if ( _num_icds != i ) {
394 picd->dl_handle = dlh;
397 picd->num_platforms = num_valid_platforms;
398 _icds[i].first_platform = _num_picds - num_valid_platforms;
406 static void __initClIcd( void ) {
408 cl_uint num_icds = 0;
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;
415 debug(D_LOG,"Reading icd list from '%s'", dir_path);
416 dir = opendir(dir_path);
421 num_icds = _find_num_icds(dir);
426 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
431 num_icds = _open_drivers(dir, dir_path);
436 _find_and_check_platforms(num_icds);
441 if (_num_icds < num_icds) {
442 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
444 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
456 static pthread_once_t once_init = PTHREAD_ONCE_INIT;
460 volatile static cl_uint _initialized = 0;
462 static inline void __attribute__((constructor)) _initClIcd( void ) {
466 pthread_once(&once_init, &__initClIcd);
468 if (__sync_bool_compare_and_swap(&gard, 0, 1)) {
471 /* someone else started __initClIcd(). We wait until its end. */
472 while (!_initialized) ;
478 #pragma GCC visibility pop
479 #define hidden_alias(name) \
480 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
482 CL_API_ENTRY void * CL_API_CALL
483 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
486 if( func_name == NULL )
488 cl_uint suffix_length;
490 void * return_value=NULL;
491 struct func_desc const * fn=&function_description[0];
492 while (fn->name != NULL) {
493 if (strcmp(func_name, fn->name)==0)
497 for(i=0; i<_num_picds; i++) {
498 suffix_length = strlen(_picds[i].extension_suffix);
499 if( suffix_length > strlen(func_name) )
501 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
502 RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
504 RETURN(return_value);
506 hidden_alias(clGetExtensionFunctionAddress);
508 CL_API_ENTRY cl_int CL_API_CALL
509 clGetPlatformIDs(cl_uint num_entries,
510 cl_platform_id * platforms,
511 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
514 if( platforms == NULL && num_platforms == NULL )
515 RETURN(CL_INVALID_VALUE);
516 if( num_entries == 0 && platforms != NULL )
517 RETURN(CL_INVALID_VALUE);
519 RETURN(CL_PLATFORM_NOT_FOUND_KHR);
522 if( num_platforms != NULL ){
523 *num_platforms = _num_picds;
525 if( platforms != NULL ) {
526 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
527 for( i=0; i<n_platforms; i++) {
528 *(platforms++) = _picds[i].pid;
533 hidden_alias(clGetPlatformIDs);
535 CL_API_ENTRY cl_context CL_API_CALL
536 clCreateContext(const cl_context_properties * properties ,
537 cl_uint num_devices ,
538 const cl_device_id * devices ,
539 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
541 cl_int * errcode_ret ){
545 if( properties != NULL){
546 while( properties[i] != 0 ) {
547 if( properties[i] == CL_CONTEXT_PLATFORM )
548 RETURN(((struct _cl_platform_id *) properties[i+1])
549 ->dispatch->clCreateContext(properties, num_devices, devices,
550 pfn_notify, user_data, errcode_ret));
554 if(devices == NULL || num_devices == 0) {
556 *errcode_ret = CL_INVALID_VALUE;
560 RETURN(((struct _cl_device_id *)devices[0])
561 ->dispatch->clCreateContext(properties, num_devices, devices,
562 pfn_notify, user_data, errcode_ret));
564 hidden_alias(clCreateContext);
566 CL_API_ENTRY cl_context CL_API_CALL
567 clCreateContextFromType(const cl_context_properties * properties ,
568 cl_device_type device_type ,
569 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
571 cl_int * errcode_ret ){
575 if( properties != NULL){
576 while( properties[i] != 0 ) {
577 if( properties[i] == CL_CONTEXT_PLATFORM )
578 if (properties[i+1] == 0) {
581 return ((struct _cl_platform_id *) properties[i+1])
582 ->dispatch->clCreateContextFromType(properties, device_type,
583 pfn_notify, user_data, errcode_ret);
587 /* if properties is null, the selected platform is implementation dependant
588 * We will use the first one if any
590 if(_num_picds == 0) {
592 *errcode_ret = CL_INVALID_VALUE;
596 RETURN(_picds[0].pid->dispatch->clCreateContextFromType
597 (properties, device_type, pfn_notify, user_data, errcode_ret));
601 *errcode_ret = CL_INVALID_PLATFORM;
605 hidden_alias(clCreateContextFromType);
607 CL_API_ENTRY cl_int CL_API_CALL
608 clGetGLContextInfoKHR(const cl_context_properties * properties ,
609 cl_gl_context_info param_name ,
610 size_t param_value_size ,
612 size_t * param_value_size_ret ){
616 if( properties != NULL){
617 while( properties[i] != 0 ) {
618 if( properties[i] == CL_CONTEXT_PLATFORM )
619 RETURN(((struct _cl_platform_id *) properties[i+1])
620 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
621 param_value_size, param_value, param_value_size_ret));
625 RETURN(CL_INVALID_PLATFORM);
627 hidden_alias(clGetGLContextInfoKHR);
629 CL_API_ENTRY cl_int CL_API_CALL
630 clWaitForEvents(cl_uint num_events ,
631 const cl_event * event_list ){
633 if( num_events == 0 || event_list == NULL )
634 RETURN(CL_INVALID_VALUE);
635 RETURN(((struct _cl_event *)event_list[0])
636 ->dispatch->clWaitForEvents(num_events, event_list));
638 hidden_alias(clWaitForEvents);
640 CL_API_ENTRY cl_int CL_API_CALL
641 clUnloadCompiler( void ){
645 hidden_alias(clUnloadCompiler);