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>4 && 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>4 && 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 FILE *f = fopen(lib_path,"r");
191 fseek(f, 0, SEEK_END);
192 lib_path_length = ftell(f)+1;
193 fseek(f, 0, SEEK_SET);
194 if(lib_path_length == 1) {
198 lib_path = malloc(lib_path_length*sizeof(char));
199 err = fgets(lib_path, lib_path_length, f);
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 _icds[num_icds].dl_handle = dlopen(lib_path, RTLD_LAZY|RTLD_LOCAL);//|RTLD_DEEPBIND);
212 if(_icds[num_icds].dl_handle != NULL) {
213 debug(D_LOG, "Loading ICD[%i] -> '%s'", num_icds, lib_path);
221 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
223 addr1=dlsym(dlh, name);
225 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
231 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
234 if (addr1 && addr2 && addr1!=addr2) {
235 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
239 if (!addr2) addr2=addr1;
243 static int _allocate_platforms(int req) {
244 static cl_uint allocated=0;
245 debug(D_LOG,"Requesting allocation for %d platforms",req);
246 if (allocated - _num_picds < req) {
248 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
250 req = req - (allocated - _num_picds);
251 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
255 RETURN(allocated - _num_picds);
258 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
259 cl_platform_id pid, cl_platform_info cname, char* sname) {
261 size_t param_value_size_ret;
262 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
263 if (error != CL_SUCCESS) {
264 debug(D_WARN, "Error %s while requesting %s in platform %p",
265 _clerror2string(error), sname, pid);
268 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
269 if (param_value == NULL) {
270 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
274 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
275 if (error != CL_SUCCESS){
277 debug(D_WARN, "Error %s while requesting %s in platform %p",
278 _clerror2string(error), sname, pid);
281 RETURN_STR(param_value);
284 static inline void _find_and_check_platforms(cl_uint num_icds) {
287 for( i=0; i<num_icds; i++){
288 debug(D_LOG, "Checking ICD %i", i);
289 struct vendor_icd *picd = &_icds[_num_icds];
290 void* dlh = _icds[i].dl_handle;
291 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
292 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
293 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
294 clGetPlatformInfo_fn plt_info_ptr =
295 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
296 if( picd->ext_fn_ptr == NULL
297 || plt_fn_ptr == NULL
298 || plt_info_ptr == NULL) {
299 debug(D_WARN, "Missing symbols in ICD, skipping it");
302 cl_uint num_platforms=0;
304 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
305 if( error != CL_SUCCESS || num_platforms == 0) {
306 debug(D_LOG, "No platform in ICD, skipping it");
309 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
310 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
311 if( error != CL_SUCCESS ){
313 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
316 cl_uint num_valid_platforms=0;
318 debug(D_LOG, "Try to load %d plateforms", num_platforms);
319 if (_allocate_platforms(num_platforms) < num_platforms) {
321 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
324 for(j=0; j<num_platforms; j++) {
325 debug(D_LOG, "Checking platform %i", j);
326 struct platform_icd *p=&_picds[_num_picds];
327 p->extension_suffix=NULL;
331 if (debug_ocl_icd_mask & D_DUMP) {
332 dump_platform(p->pid);
335 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
336 if (param_value == NULL){
337 debug(D_WARN, "Skipping platform %i", j);
340 debug(D_DUMP, "Supported extensions: %s", param_value);
341 if( strstr(param_value, "cl_khr_icd") == NULL){
343 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
347 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
348 if (param_value == NULL){
349 debug(D_WARN, "Skipping platform %i", j);
352 p->extension_suffix = param_value;
353 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
355 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
356 if (param_value != NULL){
357 debug(D_DUMP, "Profile: %s", param_value);
361 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
362 p->version = param_value;
363 if (param_value != NULL){
364 debug(D_DUMP, "Version: %s", param_value);
368 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
369 if (param_value != NULL){
370 debug(D_DUMP, "Name: %s", param_value);
373 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
374 if (param_value != NULL){
375 debug(D_DUMP, "Vendor: %s", param_value);
379 num_valid_platforms++;
382 if( num_valid_platforms != 0 ) {
383 if ( _num_icds != i ) {
384 picd->dl_handle = dlh;
387 picd->num_platforms = num_valid_platforms;
388 _icds[i].first_platform = _num_picds - num_valid_platforms;
396 static void _initClIcd( void ) {
400 char *debug=getenv("OCL_ICD_DEBUG");
402 debug_ocl_icd_mask=atoi(debug);
404 debug_ocl_icd_mask=1;
407 cl_uint num_icds = 0;
409 const char* dir_path=getenv("OCL_ICD_VENDORS");
410 if (! dir_path || dir_path[0]==0) {
411 dir_path=ETC_OPENCL_VENDORS;
413 debug(D_LOG,"Reading icd list from '%s'", dir_path);
414 dir = opendir(dir_path);
419 num_icds = _find_num_icds(dir);
424 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
429 num_icds = _open_drivers(dir, dir_path);
434 _find_and_check_platforms(num_icds);
439 if (_num_icds < num_icds) {
440 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
442 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
455 #pragma GCC visibility pop
457 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
460 if( func_name == NULL )
462 cl_uint suffix_length;
464 void * return_value=NULL;
465 struct func_desc const * fn=&function_description[0];
466 while (fn->name != NULL) {
467 if (strcmp(func_name, fn->name)==0)
471 for(i=0; i<_num_picds; i++) {
472 suffix_length = strlen(_picds[i].extension_suffix);
473 if( suffix_length > strlen(func_name) )
475 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
476 return (*_picds[i].vicd->ext_fn_ptr)(func_name);
480 typeof(clGetExtensionFunctionAddress) clGetExtensionFunctionAddress_hid __attribute__ ((alias ("clGetExtensionFunctionAddress"), visibility("hidden")));
482 CL_API_ENTRY cl_int CL_API_CALL
483 clGetPlatformIDs(cl_uint num_entries,
484 cl_platform_id * platforms,
485 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
488 if( platforms == NULL && num_platforms == NULL )
489 return CL_INVALID_VALUE;
490 if( num_entries == 0 && platforms != NULL )
491 return CL_INVALID_VALUE;
493 return CL_PLATFORM_NOT_FOUND_KHR;
496 if( num_platforms != NULL ){
497 *num_platforms = _num_picds;
499 if( platforms != NULL ) {
500 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
501 for( i=0; i<n_platforms; i++) {
502 *(platforms++) = _picds[i].pid;
507 typeof(clGetPlatformIDs) clGetPlatformIDs_hid __attribute__ ((alias ("clGetPlatformIDs"), visibility("hidden")));