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 #include "ocl_icd_loader_debug.h"
40 #define ETC_OPENCL_VENDORS "/etc/OpenCL/vendors/"
42 int debug_ocl_icd_mask=0;
44 typedef __typeof__(clGetExtensionFunctionAddress) *clGetExtensionFunctionAddress_fn;
45 typedef __typeof__(clGetPlatformInfo) *clGetPlatformInfo_fn;
49 cl_uint num_platforms;
50 cl_uint first_platform;
52 clGetExtensionFunctionAddress_fn ext_fn_ptr;
56 char * extension_suffix;
58 struct vendor_icd *vicd;
62 struct vendor_icd *_icds=NULL;
63 struct platform_icd *_picds=NULL;
64 static cl_uint _num_icds = 0;
65 static cl_uint _num_picds = 0;
67 static cl_uint _initialized = 0;
70 # define _clS(x) [-x] = #x
71 # define MAX_CL_ERRORS CL_INVALID_DEVICE_PARTITION_COUNT
72 static char const * const clErrorStr[-MAX_CL_ERRORS+1] = {
74 _clS(CL_DEVICE_NOT_FOUND),
75 _clS(CL_DEVICE_NOT_AVAILABLE),
76 _clS(CL_COMPILER_NOT_AVAILABLE),
77 _clS(CL_MEM_OBJECT_ALLOCATION_FAILURE),
78 _clS(CL_OUT_OF_RESOURCES),
79 _clS(CL_OUT_OF_HOST_MEMORY),
80 _clS(CL_PROFILING_INFO_NOT_AVAILABLE),
81 _clS(CL_MEM_COPY_OVERLAP),
82 _clS(CL_IMAGE_FORMAT_MISMATCH),
83 _clS(CL_IMAGE_FORMAT_NOT_SUPPORTED),
84 _clS(CL_BUILD_PROGRAM_FAILURE),
86 _clS(CL_MISALIGNED_SUB_BUFFER_OFFSET),
87 _clS(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST),
88 _clS(CL_COMPILE_PROGRAM_FAILURE),
89 _clS(CL_LINKER_NOT_AVAILABLE),
90 _clS(CL_LINK_PROGRAM_FAILURE),
91 _clS(CL_DEVICE_PARTITION_FAILED),
92 _clS(CL_KERNEL_ARG_INFO_NOT_AVAILABLE),
93 _clS(CL_INVALID_VALUE),
94 _clS(CL_INVALID_DEVICE_TYPE),
95 _clS(CL_INVALID_PLATFORM),
96 _clS(CL_INVALID_DEVICE),
97 _clS(CL_INVALID_CONTEXT),
98 _clS(CL_INVALID_QUEUE_PROPERTIES),
99 _clS(CL_INVALID_COMMAND_QUEUE),
100 _clS(CL_INVALID_HOST_PTR),
101 _clS(CL_INVALID_MEM_OBJECT),
102 _clS(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
103 _clS(CL_INVALID_IMAGE_SIZE),
104 _clS(CL_INVALID_SAMPLER),
105 _clS(CL_INVALID_BINARY),
106 _clS(CL_INVALID_BUILD_OPTIONS),
107 _clS(CL_INVALID_PROGRAM),
108 _clS(CL_INVALID_PROGRAM_EXECUTABLE),
109 _clS(CL_INVALID_KERNEL_NAME),
110 _clS(CL_INVALID_KERNEL_DEFINITION),
111 _clS(CL_INVALID_KERNEL),
112 _clS(CL_INVALID_ARG_INDEX),
113 _clS(CL_INVALID_ARG_VALUE),
114 _clS(CL_INVALID_ARG_SIZE),
115 _clS(CL_INVALID_KERNEL_ARGS),
116 _clS(CL_INVALID_WORK_DIMENSION),
117 _clS(CL_INVALID_WORK_GROUP_SIZE),
118 _clS(CL_INVALID_WORK_ITEM_SIZE),
119 _clS(CL_INVALID_GLOBAL_OFFSET),
120 _clS(CL_INVALID_EVENT_WAIT_LIST),
121 _clS(CL_INVALID_EVENT),
122 _clS(CL_INVALID_OPERATION),
123 _clS(CL_INVALID_GL_OBJECT),
124 _clS(CL_INVALID_BUFFER_SIZE),
125 _clS(CL_INVALID_MIP_LEVEL),
126 _clS(CL_INVALID_GLOBAL_WORK_SIZE),
127 _clS(CL_INVALID_PROPERTY),
128 _clS(CL_INVALID_IMAGE_DESCRIPTOR),
129 _clS(CL_INVALID_COMPILER_OPTIONS),
130 _clS(CL_INVALID_LINKER_OPTIONS),
131 _clS(CL_INVALID_DEVICE_PARTITION_COUNT)
136 static char* _clerror2string (cl_int error) __attribute__((unused));
137 static char* _clerror2string (cl_int error) {
139 if (-error > MAX_CL_ERRORS || error > 0) {
140 debug(D_WARN, "Unknown error code %d", error);
141 RETURN_STR("OpenCL Error");
143 const char *ret=clErrorStr[-error];
145 debug(D_WARN, "Unknown error code %d", error);
146 RETURN_STR("OpenCL Error");
150 static char number[15];
152 RETURN_STR("CL_SUCCESS");
154 snprintf(number, 15, "%i", error);
159 static inline cl_uint _find_num_icds(DIR *dir) {
160 cl_uint num_icds = 0;
162 while( (ent=readdir(dir)) != NULL ){
163 if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
165 cl_uint d_name_len = strlen(ent->d_name);
166 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
174 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
175 cl_uint num_icds = 0;
177 while( (ent=readdir(dir)) != NULL ){
178 if( strcmp(ent->d_name,".") == 0 || strcmp(ent->d_name,"..") == 0 )
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) + 1;
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) {
199 lib_path = malloc(lib_path_length*sizeof(char));
200 err = fgets(lib_path, lib_path_length, f);
207 lib_path_length = strlen(lib_path);
209 if( lib_path[lib_path_length-1] == '\n' )
210 lib_path[lib_path_length-1] = '\0';
212 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
213 if(_icds[num_icds].dl_handle != NULL) {
214 debug(D_LOG, "ICD[%i] loaded", num_icds);
222 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
224 addr1=dlsym(dlh, name);
226 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
232 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
235 if (addr1 && addr2 && addr1!=addr2) {
236 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
240 if (!addr2) addr2=addr1;
244 static int _allocate_platforms(int req) {
245 static cl_uint allocated=0;
246 debug(D_LOG,"Requesting allocation for %d platforms",req);
247 if (allocated - _num_picds < req) {
249 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
251 req = req - (allocated - _num_picds);
252 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
256 RETURN(allocated - _num_picds);
259 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
260 cl_platform_id pid, cl_platform_info cname, char* sname) {
262 size_t param_value_size_ret;
263 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
264 if (error != CL_SUCCESS) {
265 debug(D_WARN, "Error %s while requesting %s in platform %p",
266 _clerror2string(error), sname, pid);
269 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
270 if (param_value == NULL) {
271 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
275 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
276 if (error != CL_SUCCESS){
278 debug(D_WARN, "Error %s while requesting %s in platform %p",
279 _clerror2string(error), sname, pid);
282 RETURN_STR(param_value);
285 static inline void _find_and_check_platforms(cl_uint num_icds) {
288 for( i=0; i<num_icds; i++){
289 debug(D_LOG, "Checking ICD %i", i);
290 struct vendor_icd *picd = &_icds[_num_icds];
291 void* dlh = _icds[i].dl_handle;
292 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
293 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
294 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
295 clGetPlatformInfo_fn plt_info_ptr =
296 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
297 if( picd->ext_fn_ptr == NULL
298 || plt_fn_ptr == NULL
299 || plt_info_ptr == NULL) {
300 debug(D_WARN, "Missing symbols in ICD, skipping it");
303 cl_uint num_platforms=0;
305 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
306 if( error != CL_SUCCESS || num_platforms == 0) {
307 debug(D_LOG, "No platform in ICD, skipping it");
310 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
311 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
312 if( error != CL_SUCCESS ){
314 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
317 cl_uint num_valid_platforms=0;
319 debug(D_LOG, "Try to load %d plateforms", num_platforms);
320 if (_allocate_platforms(num_platforms) < num_platforms) {
322 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
325 for(j=0; j<num_platforms; j++) {
326 debug(D_LOG, "Checking platform %i", j);
327 struct platform_icd *p=&_picds[_num_picds];
328 p->extension_suffix=NULL;
332 if (debug_ocl_icd_mask & D_DUMP) {
333 dump_platform(p->pid);
336 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
337 if (param_value == NULL){
338 debug(D_WARN, "Skipping platform %i", j);
341 debug(D_DUMP, "Supported extensions: %s", param_value);
342 if( strstr(param_value, "cl_khr_icd") == NULL){
344 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
348 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
349 if (param_value == NULL){
350 debug(D_WARN, "Skipping platform %i", j);
353 p->extension_suffix = param_value;
354 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
356 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
357 if (param_value != NULL){
358 debug(D_DUMP, "Profile: %s", param_value);
362 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
363 p->version = param_value;
364 if (param_value != NULL){
365 debug(D_DUMP, "Version: %s", param_value);
369 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
370 if (param_value != NULL){
371 debug(D_DUMP, "Name: %s", param_value);
374 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
375 if (param_value != NULL){
376 debug(D_DUMP, "Vendor: %s", param_value);
380 num_valid_platforms++;
383 if( num_valid_platforms != 0 ) {
384 if ( _num_icds != i ) {
385 picd->dl_handle = dlh;
388 picd->num_platforms = num_valid_platforms;
389 _icds[i].first_platform = _num_picds - num_valid_platforms;
397 static void _initClIcd( void ) {
401 char *debug=getenv("OCL_ICD_DEBUG");
403 debug_ocl_icd_mask=atoi(debug);
405 debug_ocl_icd_mask=1;
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
458 CL_API_ENTRY void * CL_API_CALL 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 typeof(clGetExtensionFunctionAddress) clGetExtensionFunctionAddress_hid __attribute__ ((alias ("clGetExtensionFunctionAddress"), visibility("hidden")));
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 typeof(clGetPlatformIDs) clGetPlatformIDs_hid __attribute__ ((alias ("clGetPlatformIDs"), visibility("hidden")));