1 /*
2     This file is part of darktable,
3     Copyright (C) 2011-2020 darktable developers.
4 
5     darktable is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     darktable is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifdef HAVE_OPENCL
20 
21 #include "common/dlopencl.h"
22 #include "common/darktable.h"
23 #include "common/dynload.h"
24 
25 #include <assert.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #if defined(WIN32)
32 static const char *ocllib[] = { "OpenCL.dll", NULL };
33 #elif defined(__APPLE__)
34 static const char *ocllib[] = { "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", NULL };
35 #else
36 static const char *ocllib[] = { "libOpenCL", "libOpenCL.so", "libOpenCL.so.1", NULL };
37 #endif
38 
39 
40 /* only for debugging: default noop function for all unassigned function pointers */
dt_dlopencl_noop(void)41 void dt_dlopencl_noop(void)
42 {
43   /* we should normally never get here */
44   fprintf(stderr, "dt_dlopencl internal error: unsupported function call\n");
45   raise(SIGABRT);
46 }
47 
48 
49 /* dynamically load OpenCL library and bind needed symbols */
dt_dlopencl_init(const char * name)50 dt_dlopencl_t *dt_dlopencl_init(const char *name)
51 {
52   dt_gmodule_t *module = NULL;
53   dt_dlopencl_t *ocl;
54   const char *library = NULL;
55   int success;
56 
57   /* check if our platform supports gmodules */
58   success = dt_gmodule_supported();
59   if(!success) return NULL;
60 
61   /* try to load library. if a name is given check only that library - else iterate over default names. */
62   if(name != NULL && name[0] != '\0')
63   {
64     library = name;
65     module = dt_gmodule_open(library);
66     if(module == NULL)
67       dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not find opencl runtime library '%s'\n", library);
68     else
69       dt_print(DT_DEBUG_OPENCL, "[opencl_init] found opencl runtime library '%s'\n", library);
70   }
71   else
72   {
73     const char **iter = ocllib;
74     while(*iter && (module == NULL))
75     {
76       library = *iter;
77       module = dt_gmodule_open(library);
78       if(module == NULL)
79         dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not find opencl runtime library '%s'\n", library);
80       else
81         dt_print(DT_DEBUG_OPENCL, "[opencl_init] found opencl runtime library '%s'\n", library);
82       iter++;
83     }
84   }
85 
86   if(module == NULL)
87     return NULL;
88   else
89   {
90     /* now bind symbols */
91     success = TRUE;
92     ocl = (dt_dlopencl_t *)malloc(sizeof(dt_dlopencl_t));
93 
94     if(ocl == NULL)
95     {
96       free(module);
97       return NULL;
98     }
99 
100     ocl->symbols = (dt_dlopencl_symbols_t *)calloc(1, sizeof(dt_dlopencl_symbols_t));
101 
102     if(ocl->symbols == NULL)
103     {
104       free(ocl);
105       free(module);
106       return NULL;
107     }
108 
109     ocl->library = module->library;
110 
111     /* assign noop function as a default to each function pointer */
112     void (**slist)(void) = (void (**)(void))ocl->symbols;
113     /* sanity check against padding */
114     if(sizeof(dt_dlopencl_symbols_t) % sizeof(void (*)(void)) == 0)
115       for(int k = 0; k < sizeof(dt_dlopencl_symbols_t) / sizeof(void (*)(void)); k++) slist[k] = dt_dlopencl_noop;
116 
117     /* only bind needed symbols */
118     success = success && dt_gmodule_symbol(module, "clGetPlatformIDs",
119                                            (void (**)(void)) & ocl->symbols->dt_clGetPlatformIDs);
120     success = success && dt_gmodule_symbol(module, "clGetPlatformInfo",
121                                            (void (**)(void)) & ocl->symbols->dt_clGetPlatformInfo);
122     success = success && dt_gmodule_symbol(module, "clGetDeviceIDs",
123                                            (void (**)(void)) & ocl->symbols->dt_clGetDeviceIDs);
124     success = success && dt_gmodule_symbol(module, "clGetDeviceInfo",
125                                            (void (**)(void)) & ocl->symbols->dt_clGetDeviceInfo);
126     success = success && dt_gmodule_symbol(module, "clCreateContext",
127                                            (void (**)(void)) & ocl->symbols->dt_clCreateContext);
128     success = success && dt_gmodule_symbol(module, "clCreateCommandQueue",
129                                            (void (**)(void)) & ocl->symbols->dt_clCreateCommandQueue);
130     success = success && dt_gmodule_symbol(module, "clCreateProgramWithSource",
131                                            (void (**)(void)) & ocl->symbols->dt_clCreateProgramWithSource);
132     success = success && dt_gmodule_symbol(module, "clBuildProgram",
133                                            (void (**)(void)) & ocl->symbols->dt_clBuildProgram);
134     success = success && dt_gmodule_symbol(module, "clGetProgramBuildInfo",
135                                            (void (**)(void)) & ocl->symbols->dt_clGetProgramBuildInfo);
136     success = success && dt_gmodule_symbol(module, "clCreateKernel",
137                                            (void (**)(void)) & ocl->symbols->dt_clCreateKernel);
138     success = success && dt_gmodule_symbol(module, "clCreateBuffer",
139                                            (void (**)(void)) & ocl->symbols->dt_clCreateBuffer);
140     success = success && dt_gmodule_symbol(module, "clCreateImage2D",
141                                            (void (**)(void)) & ocl->symbols->dt_clCreateImage2D);
142     success = success && dt_gmodule_symbol(module, "clEnqueueWriteBuffer",
143                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueWriteBuffer);
144     success = success && dt_gmodule_symbol(module, "clSetKernelArg",
145                                            (void (**)(void)) & ocl->symbols->dt_clSetKernelArg);
146     success = success && dt_gmodule_symbol(module, "clGetKernelWorkGroupInfo",
147                                            (void (**)(void)) & ocl->symbols->dt_clGetKernelWorkGroupInfo);
148     success = success && dt_gmodule_symbol(module, "clEnqueueNDRangeKernel",
149                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueNDRangeKernel);
150     success = success && dt_gmodule_symbol(module, "clEnqueueReadImage",
151                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueReadImage);
152     success = success && dt_gmodule_symbol(module, "clEnqueueWriteImage",
153                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueWriteImage);
154     success = success && dt_gmodule_symbol(module, "clEnqueueCopyImage",
155                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueCopyImage);
156     success = success && dt_gmodule_symbol(module, "clEnqueueCopyImageToBuffer",
157                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueCopyImageToBuffer);
158     success = success && dt_gmodule_symbol(module, "clEnqueueCopyBufferToImage",
159                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueCopyBufferToImage);
160     success = success && dt_gmodule_symbol(module, "clFinish", (void (**)(void)) & ocl->symbols->dt_clFinish);
161     success = success && dt_gmodule_symbol(module, "clEnqueueReadBuffer",
162                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueReadBuffer);
163     success = success && dt_gmodule_symbol(module, "clReleaseMemObject",
164                                            (void (**)(void)) & ocl->symbols->dt_clReleaseMemObject);
165     success = success && dt_gmodule_symbol(module, "clReleaseProgram",
166                                            (void (**)(void)) & ocl->symbols->dt_clReleaseProgram);
167     success = success && dt_gmodule_symbol(module, "clReleaseKernel",
168                                            (void (**)(void)) & ocl->symbols->dt_clReleaseKernel);
169     success = success && dt_gmodule_symbol(module, "clReleaseCommandQueue",
170                                            (void (**)(void)) & ocl->symbols->dt_clReleaseCommandQueue);
171     success = success && dt_gmodule_symbol(module, "clReleaseContext",
172                                            (void (**)(void)) & ocl->symbols->dt_clReleaseContext);
173     success = success && dt_gmodule_symbol(module, "clReleaseEvent",
174                                            (void (**)(void)) & ocl->symbols->dt_clReleaseEvent);
175     success = success && dt_gmodule_symbol(module, "clWaitForEvents",
176                                            (void (**)(void)) & ocl->symbols->dt_clWaitForEvents);
177     success = success && dt_gmodule_symbol(module, "clGetEventInfo",
178                                            (void (**)(void)) & ocl->symbols->dt_clGetEventInfo);
179     success = success && dt_gmodule_symbol(module, "clGetEventProfilingInfo",
180                                            (void (**)(void)) & ocl->symbols->dt_clGetEventProfilingInfo);
181     success = success && dt_gmodule_symbol(module, "clGetKernelInfo",
182                                            (void (**)(void)) & ocl->symbols->dt_clGetKernelInfo);
183     success = success && dt_gmodule_symbol(module, "clEnqueueBarrier",
184                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueBarrier);
185     success = success && dt_gmodule_symbol(module, "clGetKernelWorkGroupInfo",
186                                            (void (**)(void)) & ocl->symbols->dt_clGetKernelWorkGroupInfo);
187     success = success && dt_gmodule_symbol(module, "clEnqueueReadBuffer",
188                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueReadBuffer);
189     success = success && dt_gmodule_symbol(module, "clEnqueueWriteBuffer",
190                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueWriteBuffer);
191     success = success && dt_gmodule_symbol(module, "clGetProgramInfo",
192                                            (void (**)(void)) & ocl->symbols->dt_clGetProgramInfo);
193     success = success && dt_gmodule_symbol(module, "clCreateProgramWithBinary",
194                                            (void (**)(void)) & ocl->symbols->dt_clCreateProgramWithBinary);
195     success = success && dt_gmodule_symbol(module, "clEnqueueCopyBuffer",
196                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueCopyBuffer);
197     success = success && dt_gmodule_symbol(module, "clEnqueueMapBuffer",
198                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueMapBuffer);
199     success = success && dt_gmodule_symbol(module, "clEnqueueUnmapMemObject",
200                                            (void (**)(void)) & ocl->symbols->dt_clEnqueueUnmapMemObject);
201     success = success && dt_gmodule_symbol(module, "clGetMemObjectInfo",
202                                            (void (**)(void)) & ocl->symbols->dt_clGetMemObjectInfo);
203     success = success && dt_gmodule_symbol(module, "clGetImageInfo",
204                                            ((void (**)(void)) & ocl->symbols->dt_clGetImageInfo));
205 
206     ocl->have_opencl = success;
207 
208     if(!success)
209       dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not load all required symbols from library\n");
210   }
211 
212   free(module);
213 
214   if(!success)
215   {
216     free(ocl->symbols);
217     free(ocl);
218     return NULL;
219   }
220 
221   return ocl;
222 }
223 
224 #endif
225 
226 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
227 // vim: shiftwidth=2 expandtab tabstop=2 cindent
228 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
229