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_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 cl_uint d_name_len = strlen(ent->d_name);
164 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
172 static inline cl_uint _open_drivers(DIR *dir, const char* dir_path) {
173 cl_uint num_icds = 0;
175 while( (ent=readdir(dir)) != NULL ){
176 cl_uint d_name_len = strlen(ent->d_name);
177 if( d_name_len<5 || strcmp(ent->d_name + d_name_len - 4, ".icd" ) != 0 )
181 unsigned int lib_path_length = strlen(dir_path) + strlen(ent->d_name) + 2;
182 lib_path = malloc(lib_path_length*sizeof(char));
183 sprintf(lib_path,"%s/%s", dir_path, ent->d_name);
184 debug(D_LOG, "Considering file '%s'", lib_path);
185 FILE *f = fopen(lib_path,"r");
188 fseek(f, 0, SEEK_END);
189 lib_path_length = ftell(f)+1;
190 fseek(f, 0, SEEK_SET);
191 if(lib_path_length == 1) {
192 debug(D_WARN, "File contents too short, skipping ICD");
196 lib_path = malloc(lib_path_length*sizeof(char));
197 err = fgets(lib_path, lib_path_length, f);
201 debug(D_WARN, "Error while loading file contents, skipping ICD");
205 lib_path_length = strlen(lib_path);
207 if( lib_path[lib_path_length-1] == '\n' )
208 lib_path[lib_path_length-1] = '\0';
210 debug(D_LOG, "Loading ICD '%s'", lib_path);
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);
217 debug(D_WARN, "error while dlopening the IDL, skipping ICD");
224 static void* _get_function_addr(void* dlh, clGetExtensionFunctionAddress_fn fn, const char*name) {
226 addr1=dlsym(dlh, name);
228 debug(D_WARN, "Missing global symbol '%s' in ICD, should be skipped", name);
234 debug(D_WARN, "Missing function '%s' in ICD, should be skipped", name);
237 if (addr1 && addr2 && addr1!=addr2) {
238 debug(D_WARN, "Function and symbol '%s' have different addresses!", name);
242 if (!addr2) addr2=addr1;
246 static int _allocate_platforms(int req) {
247 static cl_uint allocated=0;
248 debug(D_LOG,"Requesting allocation for %d platforms",req);
249 if (allocated - _num_picds < req) {
251 _picds=(struct platform_icd*)malloc(req*sizeof(struct platform_icd));
253 req = req - (allocated - _num_picds);
254 _picds=(struct platform_icd*)realloc(_picds, (allocated+req)*sizeof(struct platform_icd));
258 RETURN(allocated - _num_picds);
261 static char* _malloc_clGetPlatformInfo(clGetPlatformInfo_fn plt_info_ptr,
262 cl_platform_id pid, cl_platform_info cname, char* sname) {
264 size_t param_value_size_ret;
265 error = plt_info_ptr(pid, cname, 0, NULL, ¶m_value_size_ret);
266 if (error != CL_SUCCESS) {
267 debug(D_WARN, "Error %s while requesting %s in platform %p",
268 _clerror2string(error), sname, pid);
271 char *param_value = (char *)malloc(sizeof(char)*param_value_size_ret);
272 if (param_value == NULL) {
273 debug(D_WARN, "Error in malloc while requesting %s in platform %p",
277 error = plt_info_ptr(pid, cname, param_value_size_ret, param_value, NULL);
278 if (error != CL_SUCCESS){
280 debug(D_WARN, "Error %s while requesting %s in platform %p",
281 _clerror2string(error), sname, pid);
284 RETURN_STR(param_value);
287 static inline void _find_and_check_platforms(cl_uint num_icds) {
290 for( i=0; i<num_icds; i++){
291 debug(D_LOG, "Checking ICD %i", i);
292 struct vendor_icd *picd = &_icds[_num_icds];
293 void* dlh = _icds[i].dl_handle;
294 picd->ext_fn_ptr = _get_function_addr(dlh, NULL, "clGetExtensionFunctionAddress");
295 clIcdGetPlatformIDsKHR_fn plt_fn_ptr =
296 _get_function_addr(dlh, picd->ext_fn_ptr, "clIcdGetPlatformIDsKHR");
297 clGetPlatformInfo_fn plt_info_ptr =
298 _get_function_addr(dlh, picd->ext_fn_ptr, "clGetPlatformInfo");
299 if( picd->ext_fn_ptr == NULL
300 || plt_fn_ptr == NULL
301 || plt_info_ptr == NULL) {
302 debug(D_WARN, "Missing symbols in ICD, skipping it");
305 cl_uint num_platforms=0;
307 error = (*plt_fn_ptr)(0, NULL, &num_platforms);
308 if( error != CL_SUCCESS || num_platforms == 0) {
309 debug(D_LOG, "No platform in ICD, skipping it");
312 cl_platform_id *platforms = (cl_platform_id *) malloc( sizeof(cl_platform_id) * num_platforms);
313 error = (*plt_fn_ptr)(num_platforms, platforms, NULL);
314 if( error != CL_SUCCESS ){
316 debug(D_WARN, "Error in loading ICD platforms, skipping ICD");
319 cl_uint num_valid_platforms=0;
321 debug(D_LOG, "Try to load %d plateforms", num_platforms);
322 if (_allocate_platforms(num_platforms) < num_platforms) {
324 debug(D_WARN, "Not enought platform allocated. Skipping ICD");
327 for(j=0; j<num_platforms; j++) {
328 debug(D_LOG, "Checking platform %i", j);
329 struct platform_icd *p=&_picds[_num_picds];
330 p->extension_suffix=NULL;
334 if (debug_ocl_icd_mask & D_DUMP) {
335 dump_platform(p->pid);
338 char *param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_EXTENSIONS, "extensions");
339 if (param_value == NULL){
340 debug(D_WARN, "Skipping platform %i", j);
343 debug(D_DUMP, "Supported extensions: %s", param_value);
344 if( strstr(param_value, "cl_khr_icd") == NULL){
346 debug(D_WARN, "Missing khr extension in platform %i, skipping it", j);
350 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_ICD_SUFFIX_KHR, "suffix");
351 if (param_value == NULL){
352 debug(D_WARN, "Skipping platform %i", j);
355 p->extension_suffix = param_value;
356 debug(D_DUMP|D_LOG, "Extension suffix: %s", param_value);
358 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_PROFILE, "profile");
359 if (param_value != NULL){
360 debug(D_DUMP, "Profile: %s", param_value);
364 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VERSION, "version");
365 p->version = param_value;
366 if (param_value != NULL){
367 debug(D_DUMP, "Version: %s", param_value);
371 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_NAME, "name");
372 if (param_value != NULL){
373 debug(D_DUMP, "Name: %s", param_value);
376 param_value=_malloc_clGetPlatformInfo(plt_info_ptr, p->pid, CL_PLATFORM_VENDOR, "vendor");
377 if (param_value != NULL){
378 debug(D_DUMP, "Vendor: %s", param_value);
382 num_valid_platforms++;
385 if( num_valid_platforms != 0 ) {
386 if ( _num_icds != i ) {
387 picd->dl_handle = dlh;
390 picd->num_platforms = num_valid_platforms;
391 _icds[i].first_platform = _num_picds - num_valid_platforms;
399 static void _initClIcd( void ) {
403 cl_uint num_icds = 0;
405 const char* dir_path=getenv("OCL_ICD_VENDORS");
406 if (! dir_path || dir_path[0]==0) {
407 dir_path=ETC_OPENCL_VENDORS;
409 debug(D_LOG,"Reading icd list from '%s'", dir_path);
410 dir = opendir(dir_path);
415 num_icds = _find_num_icds(dir);
420 _icds = (struct vendor_icd*)malloc(num_icds * sizeof(struct vendor_icd));
425 num_icds = _open_drivers(dir, dir_path);
430 _find_and_check_platforms(num_icds);
435 if (_num_icds < num_icds) {
436 _icds = (struct vendor_icd*)realloc(_icds, _num_icds * sizeof(struct vendor_icd));
438 debug(D_WARN, "%d valid vendor(s)!", _num_icds);
451 #pragma GCC visibility pop
453 CL_API_ENTRY void * CL_API_CALL clGetExtensionFunctionAddress(const char * func_name) CL_API_SUFFIX__VERSION_1_0 {
456 if( func_name == NULL )
458 cl_uint suffix_length;
460 void * return_value=NULL;
461 struct func_desc const * fn=&function_description[0];
462 while (fn->name != NULL) {
463 if (strcmp(func_name, fn->name)==0)
467 for(i=0; i<_num_picds; i++) {
468 suffix_length = strlen(_picds[i].extension_suffix);
469 if( suffix_length > strlen(func_name) )
471 if(strcmp(_picds[i].extension_suffix, &func_name[strlen(func_name)-suffix_length]) == 0)
472 return (*_picds[i].vicd->ext_fn_ptr)(func_name);
476 typeof(clGetExtensionFunctionAddress) clGetExtensionFunctionAddress_hid __attribute__ ((alias ("clGetExtensionFunctionAddress"), visibility("hidden")));
478 CL_API_ENTRY cl_int CL_API_CALL
479 clGetPlatformIDs(cl_uint num_entries,
480 cl_platform_id * platforms,
481 cl_uint * num_platforms) CL_API_SUFFIX__VERSION_1_0 {
484 if( platforms == NULL && num_platforms == NULL )
485 return CL_INVALID_VALUE;
486 if( num_entries == 0 && platforms != NULL )
487 return CL_INVALID_VALUE;
489 return CL_PLATFORM_NOT_FOUND_KHR;
492 if( num_platforms != NULL ){
493 *num_platforms = _num_picds;
495 if( platforms != NULL ) {
496 cl_uint n_platforms = _num_picds < num_entries ? _num_picds : num_entries;
497 for( i=0; i<n_platforms; i++) {
498 *(platforms++) = _picds[i].pid;
503 typeof(clGetPlatformIDs) clGetPlatformIDs_hid __attribute__ ((alias ("clGetPlatformIDs"), visibility("hidden")));