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 #define CL_USE_DEPRECATED_OPENCL_1_1_APIS
33 #include <CL/opencl.h>
35 #pragma GCC visibility push(hidden)
37 #include "ocl_icd_loader.h"
38 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
39 #include "ocl_icd_debug.h"
41 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
43 int debug_ocl_icd_mask=0;
45 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
46 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
50 cl_uint num_platforms;
51 cl_uint first_platform;
53 clGetExtensionFunctionAddress_fn ext_fn_ptr;
57 char * extension_suffix;
59 struct vendor_icd *vicd;
63 struct vendor_icd *_icds=NULL;
64 struct platform_icd *_picds=NULL;
65 static cl_uint _num_icds = 0;
66 static cl_uint _num_picds = 0;
68 static cl_uint _initialized = 0;
71 # define _clS(x) [-x] = #x
72 # define MAX_CL_ERRORS CL_INVALID_DEVICE_PARTITION_COUNT
73 static char const * const clErrorStr[-MAX_CL_ERRORS+1] = {
75 _clS(CL_DEVICE_NOT_FOUND),
76 _clS(CL_DEVICE_NOT_AVAILABLE),
77 _clS(CL_COMPILER_NOT_AVAILABLE),
78 _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
79 _clS(CL_OUT_OF_RESOURCES),
80 _clS(CL_OUT_OF_HOST_MEMORY),
81 _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
82 _clS(CL_MEM_COPY_OVERLAP),
83 _clS(CL_IMAGE_FORMAT_MISMATCH),
84 _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
85 _clS(CL_BUILD_PROGRAM_FAILURE),
87 _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
88 _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
89 _clS(CL_COMPILE_PROGRAM_FAILURE),
90 _clS(CL_LINKER_NOT_AVAILABLE),
91 _clS(CL_LINK_PROGRAM_FAILURE),
92 _clS(CL_DEVICE_PARTITION_FAILED),
93 _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
94 _clS(CL_INVALID_VALUE),
95 _clS(CL_INVALID_DEVICE_TYPE),
96 _clS(CL_INVALID_PLATFORM),
97 _clS(CL_INVALID_DEVICE),
98 _clS(CL_INVALID_CONTEXT),
99 _clS(CL_INVALID_QUEUE_PROPERTIES),
100 _clS(CL_INVALID_COMMAND_QUEUE),
101 _clS(CL_INVALID_HOST_PTR),
102 _clS(CL_INVALID_MEM_OBJECT),
103 _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
104 _clS(CL_INVALID_IMAGE_SIZE),
105 _clS(CL_INVALID_SAMPLER),
106 _clS(CL_INVALID_BINARY),
107 _clS(CL_INVALID_BUILD_OPTIONS),
108 _clS(CL_INVALID_PROGRAM),
109 _clS(CL_INVALID_PROGRAM_EXECUTABLE),
110 _clS(CL_INVALID_KERNEL_NAME),
111 _clS(CL_INVALID_KERNEL_DEFINITION),
112 _clS(CL_INVALID_KERNEL),
113 _clS(CL_INVALID_ARG_INDEX),
114 _clS(CL_INVALID_ARG_VALUE),
115 _clS(CL_INVALID_ARG_SIZE),
116 _clS(CL_INVALID_KERNEL_ARGS),
117 _clS(CL_INVALID_WORK_DIMENSION),
118 _clS(CL_INVALID_WORK_GROUP_SIZE),
119 _clS(CL_INVALID_WORK_ITEM_SIZE),
120 _clS(CL_INVALID_GLOBAL_OFFSET),
121 _clS(CL_INVALID_EVENT_WAIT_LIST),
122 _clS(CL_INVALID_EVENT),
123 _clS(CL_INVALID_OPERATION),
124 _clS(CL_INVALID_GL_OBJECT),
125 _clS(CL_INVALID_BUFFER_SIZE),
126 _clS(CL_INVALID_MIP_LEVEL),
127 _clS(CL_INVALID_GLOBAL_WORK_SIZE),
128 _clS(CL_INVALID_PROPERTY),
129 _clS(CL_INVALID_IMAGE_DESCRIPTOR),
130 _clS(CL_INVALID_COMPILER_OPTIONS),
131 _clS(CL_INVALID_LINKER_OPTIONS),
132 _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
137 static char* _clerror2string (cl_int error) __attribute__((unused));
138 static char* _clerror2string (cl_int error) {
140 if (-error > MAX_CL_ERRORS || error > 0) {
141 debug(D_WARN, "Unknown error code %d", error);
142 RETURN_STR("OpenCL Error");
144 const char *ret=clErrorStr[-error];
146 debug(D_WARN, "Unknown error code %d", error);
147 RETURN_STR("OpenCL Error");
151 static char number[15];
153 RETURN_STR("CL_SUCCESS");
155 snprintf(number, 15, "%i", error);
160 static inline cl_uint _find_num_icds(DIR *dir) {
161 cl_uint num_icds = 0;
163 while( (ent=readdir(dir)) != NULL ){
164 cl_uint d_name_len = strlen(ent->d_name);
165 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
173 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
174 cl_uint num_icds = 0;
176 while( (ent=readdir(dir)) != NULL ){
177 cl_uint d_name_len = strlen(ent->d_name);
178 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
182 unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
183 lib_path = malloc(lib_path_length*sizeof(char));
184 sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
185 debug(D_LOG, "Considering file '%s'", lib_path);
186 FILE *f = fopen(lib_path,"r");
189 fseek(f, 0, SEEK_END);
190 lib_path_length = ftell(f)+1;
191 fseek(f, 0, SEEK_SET);
192 if(lib_path_length == 1) {
193 debug(D_WARN, "File contents too short, skipping ICD");
197 lib_path = malloc(lib_path_length*sizeof(char));
198 err = fgets(lib_path, lib_path_length, f);
202 debug(D_WARN, "Error while loading file contents, skipping ICD");
206 lib_path_length = strlen(lib_path);
208 if( lib_path[lib_path_length-1] == '\n' )
209 lib_path[lib_path_length-1] = '\0';
211 debug(D_LOG, "Loading ICD '%s'", lib_path);
213 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
214 if(_icds[num_icds].dl_handle != NULL) {
215 debug(D_LOG, "ICD[%i] loaded", num_icds);
218 debug(D_WARN, "error while dlopening the IDL, skipping ICD");
225 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
227 debug(D_LOG,"Looking for function %s",name);
228 addr1=dlsym(dlh, name);
230 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
236 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
239 if (addr1 && addr2 && addr1!=addr2) {
240 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
244 if (!addr2) addr2=addr1;
248 static int _allocate_platforms(int req) {
249 static cl_uint allocated=0;
250 debug(D_LOG,"Requesting allocation for %d platforms",req);
251 if (allocated - _num_picds < req) {
253 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
255 req = req - (allocated - _num_picds);
256 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
260 RETURN(allocated - _num_picds);
263 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
264 cl_platform_id pid, cl_platform_info cname, char* sname) {
266 size_t param_value_size_ret;
267 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
268 if (error != CL_SUCCESS) {
269 debug(D_WARN, "Error %s while requesting %s in platform %p",
270 _clerror2string(error), sname, pid);
273 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
274 if (param_value == NULL) {
275 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
279 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
280 if (error != CL_SUCCESS){
282 debug(D_WARN, "Error %s while requesting %s in platform %p",
283 _clerror2string(error), sname, pid);
286 RETURN_STR(param_value);
289 static inline void _find_and_check_platforms(cl_uint num_icds) {
292 for( i=0; i<num_icds; i++){
293 debug(D_LOG, "Checking ICD %i", i);
294 struct vendor_icd *picd = &_icds[_num_icds];
295 void* dlh = _icds[i].dl_handle;
296 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
297 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
298 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
299 clGetPlatformInfo_fn plt_info_ptr =
300 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
301 if( picd->ext_fn_ptr == NULL
302 || plt_fn_ptr == NULL
303 || plt_info_ptr == NULL) {
304 debug(D_WARN, "Missing symbols in ICD, skipping it");
307 cl_uint num_platforms=0;
309 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
310 if( error != CL_SUCCESS || num_platforms == 0) {
311 debug(D_LOG, "No platform in ICD, skipping it");
314 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
315 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
316 if( error != CL_SUCCESS ){
318 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
321 cl_uint num_valid_platforms=0;
323 debug(D_LOG, "Try to load %d plateforms", num_platforms);
324 if (_allocate_platforms(num_platforms) < num_platforms) {
326 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
329 for(j=0; j<num_platforms; j++) {
330 debug(D_LOG, "Checking platform %i", j);
331 struct platform_icd *p=&_picds[_num_picds];
332 p->extension_suffix=NULL;
336 if (debug_ocl_icd_mask & D_DUMP) {
337 dump_platform(p->vicd->ext_fn_ptr, p->pid);
340 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
341 if (param_value == NULL){
342 debug(D_WARN, "Skipping platform %i", j);
345 debug(D_DUMP, "Supported extensions: %s", param_value);
346 if( strstr(param_value, "cl_khr_icd") == NULL){
348 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
352 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
353 if (param_value == NULL){
354 debug(D_WARN, "Skipping platform %i", j);
357 p->extension_suffix = param_value;
358 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
360 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
361 if (param_value != NULL){
362 debug(D_DUMP, "Profile: %s", param_value);
366 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
367 p->version = param_value;
368 if (param_value != NULL){
369 debug(D_DUMP, "Version: %s", param_value);
373 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
374 if (param_value != NULL){
375 debug(D_DUMP, "Name: %s", param_value);
378 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
379 if (param_value != NULL){
380 debug(D_DUMP, "Vendor: %s", param_value);
384 num_valid_platforms++;
387 if( num_valid_platforms != 0 ) {
388 if ( _num_icds != i ) {
389 picd->dl_handle = dlh;
392 picd->num_platforms = num_valid_platforms;
393 _icds[i].first_platform = _num_picds - num_valid_platforms;
401 static void _initClIcd( void ) {
405 cl_uint num_icds = 0;
407 const char* dir_path=getenv("OCL_ICD_VENDORS");
408 if (! dir_path || dir_path[0]==0) {
409 dir_path=ETC_OPENCL_VENDORS;
411 debug(D_LOG,"Reading icd list from '%s'", dir_path);
412 dir = opendir(dir_path);
417 num_icds = _find_num_icds(dir);
422 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
427 num_icds = _open_drivers(dir, dir_path);
432 _find_and_check_platforms(num_icds);
437 if (_num_icds < num_icds) {
438 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
440 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
453 #pragma GCC visibility pop
454 #define hidden_alias(name) \
455 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
457 CL_API_ENTRY void * CL_API_CALL
458 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
461 if( func_name == NULL )
463 cl_uint suffix_length;
465 void * return_value=NULL;
466 struct func_desc const * fn=&function_description[0];
467 while (fn->name != NULL) {
468 if (strcmp(func_name, fn->name)==0)
472 for(i=0; i<_num_picds; i++) {
473 suffix_length = strlen(_picds[i].extension_suffix);
474 if( suffix_length > strlen(func_name) )
476 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
477 return (*_picds[i].vicd->ext_fn_ptr)(func_name);
481 hidden_alias(clGetExtensionFunctionAddress);
483 CL_API_ENTRY cl_int CL_API_CALL
484 clGetPlatformIDs(cl_uint num_entries,
485 cl_platform_id * platforms,
486 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
489 if( platforms == NULL && num_platforms == NULL )
490 return CL_INVALID_VALUE;
491 if( num_entries == 0 && platforms != NULL )
492 return CL_INVALID_VALUE;
494 return CL_PLATFORM_NOT_FOUND_KHR;
497 if( num_platforms != NULL ){
498 *num_platforms = _num_picds;
500 if( platforms != NULL ) {
501 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
502 for( i=0; i<n_platforms; i++) {
503 *(platforms++) = _picds[i].pid;
508 hidden_alias(clGetPlatformIDs);
510 CL_API_ENTRY cl_context CL_API_CALL
511 clCreateContext(const cl_context_properties * properties ,
512 cl_uint num_devices ,
513 const cl_device_id * devices ,
514 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
516 cl_int * errcode_ret ){
518 if( properties != NULL){
519 while( properties[i] != 0 ) {
520 if( properties[i] == CL_CONTEXT_PLATFORM )
521 return ((struct _cl_platform_id *) properties[i+1])
522 ->dispatch->clCreateContext(properties, num_devices, devices,
523 pfn_notify, user_data, errcode_ret);
527 if(devices == NULL || num_devices == 0) {
529 *errcode_ret = CL_INVALID_VALUE;
533 return ((struct _cl_device_id *)devices[0])
534 ->dispatch->clCreateContext(properties, num_devices, devices,
535 pfn_notify, user_data, errcode_ret);
537 hidden_alias(clCreateContext);
539 CL_API_ENTRY cl_context CL_API_CALL
540 clCreateContextFromType(const cl_context_properties * properties ,
541 cl_device_type device_type ,
542 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
544 cl_int * errcode_ret ){
546 if( properties != NULL){
547 while( properties[i] != 0 ) {
548 if( properties[i] == CL_CONTEXT_PLATFORM )
549 if (properties[i+1] == 0) {
552 return ((struct _cl_platform_id *) properties[i+1])
553 ->dispatch->clCreateContextFromType(properties, device_type,
554 pfn_notify, user_data, errcode_ret);
560 *errcode_ret = CL_INVALID_PLATFORM;
564 hidden_alias(clCreateContextFromType);
566 CL_API_ENTRY cl_int CL_API_CALL
567 clGetGLContextInfoKHR(const cl_context_properties * properties ,
568 cl_gl_context_info param_name ,
569 size_t param_value_size ,
571 size_t * param_value_size_ret ){
573 if( properties != NULL){
574 while( properties[i] != 0 ) {
575 if( properties[i] == CL_CONTEXT_PLATFORM )
576 return ((struct _cl_platform_id *) properties[i+1])
577 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
578 param_value_size, param_value, param_value_size_ret);
582 return CL_INVALID_PLATFORM;
584 hidden_alias(clGetGLContextInfoKHR);
586 CL_API_ENTRY cl_int CL_API_CALL
587 clWaitForEvents(cl_uint num_events ,
588 const cl_event * event_list ){
589 if( num_events == 0 || event_list == NULL )
590 return CL_INVALID_VALUE;
591 return ((struct _cl_event *)event_list[0])
592 ->dispatch->clWaitForEvents(num_events, event_list);
594 hidden_alias(clWaitForEvents);
596 CL_API_ENTRY cl_int CL_API_CALL
597 clUnloadCompiler( void ){
600 hidden_alias(clUnloadCompiler);