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 #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
38 #pragma GCC visibility push(hidden)
40 #include "ocl_icd_loader.h"
41 #define DEBUG_OCL_ICD_PROVIDE_DUMP_FIELD
42 #include "ocl_icd_debug.h"
44 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors"
46 int debug_ocl_icd_mask=0;
48 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
49 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
53 cl_uint num_platforms;
54 cl_uint first_platform;
56 clGetExtensionFunctionAddress_fn ext_fn_ptr;
60 char * extension_suffix;
62 struct vendor_icd *vicd;
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;
71 static cl_uint _initialized = 0;
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] = {
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),
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)
140 static char* _clerror2string (cl_int error) __attribute__((unused));
141 static char* _clerror2string (cl_int error) {
143 if (-error > MAX_CL_ERRORS || error > 0) {
144 debug(D_WARN, "Unknown error code %d", error);
145 RETURN_STR("OpenCL Error");
147 const char *ret=clErrorStr[-error];
149 debug(D_WARN, "Unknown error code %d", error);
150 RETURN_STR("OpenCL Error");
154 static char number[15];
156 RETURN_STR("CL_SUCCESS");
158 snprintf(number, 15, "%i", error);
163 static inline cl_uint _find_num_icds(DIR *dir) {
164 cl_uint num_icds = 0;
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 )
176 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
177 cl_uint num_icds = 0;
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 )
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");
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");
200 lib_path = malloc(lib_path_length*sizeof(char));
201 err = fgets(lib_path, lib_path_length, f);
205 debug(D_WARN, "Error while loading file contents, skipping ICD");
209 lib_path_length = strlen(lib_path);
211 if( lib_path[lib_path_length-1] == '\n' )
212 lib_path[lib_path_length-1] = '\0';
214 debug(D_LOG, "Loading ICD '%s'", lib_path);
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);
221 debug(D_WARN, "error while dlopening the IDL, skipping ICD");
228 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
230 debug(D_LOG,"Looking for function %s",name);
231 addr1=dlsym(dlh, name);
233 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
239 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
242 if (addr1 && addr2 && addr1!=addr2) {
243 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
247 if (!addr2) addr2=addr1;
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) {
256 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
258 req = req - (allocated - _num_picds);
259 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
263 RETURN(allocated - _num_picds);
266 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
267 cl_platform_id pid, cl_platform_info cname, char* sname) {
269 size_t param_value_size_ret;
270 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_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);
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",
282 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
283 if (error != CL_SUCCESS){
285 debug(D_WARN, "Error %s while requesting %s in platform %p",
286 _clerror2string(error), sname, pid);
289 RETURN_STR(param_value);
292 static inline void _find_and_check_platforms(cl_uint num_icds) {
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");
310 cl_uint num_platforms=0;
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");
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 ){
321 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
324 cl_uint num_valid_platforms=0;
326 debug(D_LOG, "Try to load %d plateforms", num_platforms);
327 if (_allocate_platforms(num_platforms) < num_platforms) {
329 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
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;
339 if (debug_ocl_icd_mask & D_DUMP) {
340 dump_platform(p->vicd->ext_fn_ptr, p->pid);
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);
348 debug(D_DUMP, "Supported extensions: %s", param_value);
349 if( strstr(param_value, "cl_khr_icd") == NULL){
351 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
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);
360 p->extension_suffix = param_value;
361 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
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);
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);
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);
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);
387 num_valid_platforms++;
390 if( num_valid_platforms != 0 ) {
391 if ( _num_icds != i ) {
392 picd->dl_handle = dlh;
395 picd->num_platforms = num_valid_platforms;
396 _icds[i].first_platform = _num_picds - num_valid_platforms;
404 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);
457 #pragma GCC visibility pop
458 #define hidden_alias(name) \
459 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
461 CL_API_ENTRY void * CL_API_CALL
462 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
466 if( func_name == NULL )
468 cl_uint suffix_length;
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)
477 for(i=0; i<_num_picds; i++) {
478 suffix_length = strlen(_picds[i].extension_suffix);
479 if( suffix_length > strlen(func_name) )
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));
484 RETURN(return_value);
486 hidden_alias(clGetExtensionFunctionAddress);
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 {
495 if( platforms == NULL && num_platforms == NULL )
496 RETURN(CL_INVALID_VALUE);
497 if( num_entries == 0 && platforms != NULL )
498 RETURN(CL_INVALID_VALUE);
500 RETURN(CL_PLATFORM_NOT_FOUND_KHR);
503 if( num_platforms != NULL ){
504 *num_platforms = _num_picds;
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;
514 hidden_alias(clGetPlatformIDs);
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 *),
522 cl_int * errcode_ret ){
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));
536 if(devices == NULL || num_devices == 0) {
538 *errcode_ret = CL_INVALID_VALUE;
542 RETURN(((struct _cl_device_id *)devices[0])
543 ->dispatch->clCreateContext(properties, num_devices, devices,
544 pfn_notify, user_data, errcode_ret));
546 hidden_alias(clCreateContext);
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 *),
553 cl_int * errcode_ret ){
558 if( properties != NULL){
559 while( properties[i] != 0 ) {
560 if( properties[i] == CL_CONTEXT_PLATFORM )
561 if (properties[i+1] == 0) {
564 return ((struct _cl_platform_id *) properties[i+1])
565 ->dispatch->clCreateContextFromType(properties, device_type,
566 pfn_notify, user_data, errcode_ret);
570 /* if properties is null, the selected platform is implementation dependant
571 * We will use the first one if any
573 if(_num_picds == 0) {
575 *errcode_ret = CL_INVALID_VALUE;
579 RETURN(_picds[0].pid->dispatch->clCreateContextFromType
580 (properties, device_type, pfn_notify, user_data, errcode_ret));
584 *errcode_ret = CL_INVALID_PLATFORM;
588 hidden_alias(clCreateContextFromType);
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 ,
595 size_t * param_value_size_ret ){
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));
609 RETURN(CL_INVALID_PLATFORM);
611 hidden_alias(clGetGLContextInfoKHR);
613 CL_API_ENTRY cl_int CL_API_CALL
614 clWaitForEvents(cl_uint num_events ,
615 const cl_event * event_list ){
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));
622 hidden_alias(clWaitForEvents);
624 CL_API_ENTRY cl_int CL_API_CALL
625 clUnloadCompiler( void ){
629 hidden_alias(clUnloadCompiler);