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 ) {
409 cl_uint num_icds = 0;
411 const char* dir_path=getenv("OCL_ICD_VENDORS");
412 if (! dir_path || dir_path[0]==0) {
413 debug(D_DUMP, "OCL_ICD_VENDORS empty or not defined, using %s", ETC_OPENCL_VENDORS);
414 dir_path=ETC_OPENCL_VENDORS;
416 debug(D_LOG,"Reading icd list from '%s'", dir_path);
417 dir = opendir(dir_path);
422 num_icds = _find_num_icds(dir);
427 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
432 num_icds = _open_drivers(dir, dir_path);
437 _find_and_check_platforms(num_icds);
442 if (_num_icds < num_icds) {
443 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
445 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
456 #pragma GCC visibility pop
457 #define hidden_alias(name) \
458 typeof(name) name##_hid __attribute__ ((alias (#name), visibility("hidden")))
460 CL_API_ENTRY void * CL_API_CALL
461 clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
465 if( func_name == NULL )
467 cl_uint suffix_length;
469 void * return_value=NULL;
470 struct func_desc const * fn=&function_description[0];
471 while (fn->name != NULL) {
472 if (strcmp(func_name, fn->name)==0)
476 for(i=0; i<_num_picds; i++) {
477 suffix_length = strlen(_picds[i].extension_suffix);
478 if( suffix_length > strlen(func_name) )
480 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
481 RETURN((*_picds[i].vicd->ext_fn_ptr)(func_name));
483 RETURN(return_value);
485 hidden_alias(clGetExtensionFunctionAddress);
487 CL_API_ENTRY cl_int CL_API_CALL
488 clGetPlatformIDs(cl_uint num_entries,
489 cl_platform_id * platforms,
490 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
494 if( platforms == NULL && num_platforms == NULL )
495 RETURN(CL_INVALID_VALUE);
496 if( num_entries == 0 && platforms != NULL )
497 RETURN(CL_INVALID_VALUE);
499 RETURN(CL_PLATFORM_NOT_FOUND_KHR);
502 if( num_platforms != NULL ){
503 *num_platforms = _num_picds;
505 if( platforms != NULL ) {
506 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
507 for( i=0; i<n_platforms; i++) {
508 *(platforms++) = _picds[i].pid;
513 hidden_alias(clGetPlatformIDs);
515 CL_API_ENTRY cl_context CL_API_CALL
516 clCreateContext(const cl_context_properties * properties ,
517 cl_uint num_devices ,
518 const cl_device_id * devices ,
519 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
521 cl_int * errcode_ret ){
526 if( properties != NULL){
527 while( properties[i] != 0 ) {
528 if( properties[i] == CL_CONTEXT_PLATFORM )
529 RETURN(((struct _cl_platform_id *) properties[i+1])
530 ->dispatch->clCreateContext(properties, num_devices, devices,
531 pfn_notify, user_data, errcode_ret));
535 if(devices == NULL || num_devices == 0) {
537 *errcode_ret = CL_INVALID_VALUE;
541 RETURN(((struct _cl_device_id *)devices[0])
542 ->dispatch->clCreateContext(properties, num_devices, devices,
543 pfn_notify, user_data, errcode_ret));
545 hidden_alias(clCreateContext);
547 CL_API_ENTRY cl_context CL_API_CALL
548 clCreateContextFromType(const cl_context_properties * properties ,
549 cl_device_type device_type ,
550 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
552 cl_int * errcode_ret ){
557 if( properties != NULL){
558 while( properties[i] != 0 ) {
559 if( properties[i] == CL_CONTEXT_PLATFORM )
560 if (properties[i+1] == 0) {
563 return ((struct _cl_platform_id *) properties[i+1])
564 ->dispatch->clCreateContextFromType(properties, device_type,
565 pfn_notify, user_data, errcode_ret);
569 /* if properties is null, the selected platform is implementation dependant
570 * We will use the first one if any
572 if(_num_picds == 0) {
574 *errcode_ret = CL_INVALID_VALUE;
578 RETURN(_picds[0].pid->dispatch->clCreateContextFromType
579 (properties, device_type, pfn_notify, user_data, errcode_ret));
583 *errcode_ret = CL_INVALID_PLATFORM;
587 hidden_alias(clCreateContextFromType);
589 CL_API_ENTRY cl_int CL_API_CALL
590 clGetGLContextInfoKHR(const cl_context_properties * properties ,
591 cl_gl_context_info param_name ,
592 size_t param_value_size ,
594 size_t * param_value_size_ret ){
599 if( properties != NULL){
600 while( properties[i] != 0 ) {
601 if( properties[i] == CL_CONTEXT_PLATFORM )
602 RETURN(((struct _cl_platform_id *) properties[i+1])
603 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
604 param_value_size, param_value, param_value_size_ret));
608 RETURN(CL_INVALID_PLATFORM);
610 hidden_alias(clGetGLContextInfoKHR);
612 CL_API_ENTRY cl_int CL_API_CALL
613 clWaitForEvents(cl_uint num_events ,
614 const cl_event * event_list ){
616 if( num_events == 0 || event_list == NULL )
617 RETURN(CL_INVALID_VALUE);
618 RETURN(((struct _cl_event *)event_list[0])
619 ->dispatch->clWaitForEvents(num_events, event_list));
621 hidden_alias(clWaitForEvents);
623 CL_API_ENTRY cl_int CL_API_CALL
624 clUnloadCompiler( void ){
628 hidden_alias(clUnloadCompiler);