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 dir_path=ETC_OPENCL_VENDORS;
414 debug(D_LOG,"Reading icd list from '%s'", dir_path);
415 dir = opendir(dir_path);
420 num_icds = _find_num_icds(dir);
425 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
430 num_icds = _open_drivers(dir, dir_path);
435 _find_and_check_platforms(num_icds);
440 if (_num_icds < num_icds) {
441 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
443 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 {
464 if( func_name == NULL )
466 cl_uint suffix_length;
468 void * return_value=NULL;
469 struct func_desc const * fn=&function_description[0];
470 while (fn->name != NULL) {
471 if (strcmp(func_name, fn->name)==0)
475 for(i=0; i<_num_picds; i++) {
476 suffix_length = strlen(_picds[i].extension_suffix);
477 if( suffix_length > strlen(func_name) )
479 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
480 return (*_picds[i].vicd->ext_fn_ptr)(func_name);
484 hidden_alias(clGetExtensionFunctionAddress);
486 CL_API_ENTRY cl_int CL_API_CALL
487 clGetPlatformIDs(cl_uint num_entries,
488 cl_platform_id * platforms,
489 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
492 if( platforms == NULL && num_platforms == NULL )
493 return CL_INVALID_VALUE;
494 if( num_entries == 0 && platforms != NULL )
495 return CL_INVALID_VALUE;
497 return CL_PLATFORM_NOT_FOUND_KHR;
500 if( num_platforms != NULL ){
501 *num_platforms = _num_picds;
503 if( platforms != NULL ) {
504 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
505 for( i=0; i<n_platforms; i++) {
506 *(platforms++) = _picds[i].pid;
511 hidden_alias(clGetPlatformIDs);
513 CL_API_ENTRY cl_context CL_API_CALL
514 clCreateContext(const cl_context_properties * properties ,
515 cl_uint num_devices ,
516 const cl_device_id * devices ,
517 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
519 cl_int * errcode_ret ){
521 if( properties != NULL){
522 while( properties[i] != 0 ) {
523 if( properties[i] == CL_CONTEXT_PLATFORM )
524 return ((struct _cl_platform_id *) properties[i+1])
525 ->dispatch->clCreateContext(properties, num_devices, devices,
526 pfn_notify, user_data, errcode_ret);
530 if(devices == NULL || num_devices == 0) {
532 *errcode_ret = CL_INVALID_VALUE;
536 return ((struct _cl_device_id *)devices[0])
537 ->dispatch->clCreateContext(properties, num_devices, devices,
538 pfn_notify, user_data, errcode_ret);
540 hidden_alias(clCreateContext);
542 CL_API_ENTRY cl_context CL_API_CALL
543 clCreateContextFromType(const cl_context_properties * properties ,
544 cl_device_type device_type ,
545 void (CL_CALLBACK * pfn_notify )(const char *, const void *, size_t, void *),
547 cl_int * errcode_ret ){
549 if( properties != NULL){
550 while( properties[i] != 0 ) {
551 if( properties[i] == CL_CONTEXT_PLATFORM )
552 if (properties[i+1] == 0) {
555 return ((struct _cl_platform_id *) properties[i+1])
556 ->dispatch->clCreateContextFromType(properties, device_type,
557 pfn_notify, user_data, errcode_ret);
563 *errcode_ret = CL_INVALID_PLATFORM;
567 hidden_alias(clCreateContextFromType);
569 CL_API_ENTRY cl_int CL_API_CALL
570 clGetGLContextInfoKHR(const cl_context_properties * properties ,
571 cl_gl_context_info param_name ,
572 size_t param_value_size ,
574 size_t * param_value_size_ret ){
576 if( properties != NULL){
577 while( properties[i] != 0 ) {
578 if( properties[i] == CL_CONTEXT_PLATFORM )
579 return ((struct _cl_platform_id *) properties[i+1])
580 ->dispatch->clGetGLContextInfoKHR(properties, param_name,
581 param_value_size, param_value, param_value_size_ret);
585 return CL_INVALID_PLATFORM;
587 hidden_alias(clGetGLContextInfoKHR);
589 CL_API_ENTRY cl_int CL_API_CALL
590 clWaitForEvents(cl_uint num_events ,
591 const cl_event * event_list ){
592 if( num_events == 0 || event_list == NULL )
593 return CL_INVALID_VALUE;
594 return ((struct _cl_event *)event_list[0])
595 ->dispatch->clWaitForEvents(num_events, event_list);
597 hidden_alias(clWaitForEvents);
599 CL_API_ENTRY cl_int CL_API_CALL
600 clUnloadCompiler( void ){
603 hidden_alias(clUnloadCompiler);