WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / opencl.c
blobc74b675a7dca190fa5b2884f88e6519d86b374a8
1 /* opencl.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #ifdef _WIN32
11 #include <windows.h>
12 #define HB_OCL_DLOPEN LoadLibraryW(L"OpenCL")
13 #define HB_OCL_DLSYM GetProcAddress
14 #define HB_OCL_DLCLOSE FreeLibrary
15 #else
16 #include <dlfcn.h>
17 #ifdef __APPLE__
18 #define HB_OCL_DLOPEN dlopen("/System/Library/Frameworks/OpenCL.framework/OpenCL", RTLD_NOW)
19 #else
20 #define HB_OCL_DLOPEN dlopen("libOpenCL.so", RTLD_NOW)
21 #endif
22 #define HB_OCL_DLSYM dlsym
23 #define HB_OCL_DLCLOSE dlclose
24 #endif
26 #include "common.h"
27 #include "opencl.h"
29 hb_opencl_library_t *hb_ocl = NULL;
31 int hb_ocl_init()
33 if (hb_ocl == NULL)
35 if ((hb_ocl = hb_opencl_library_init()) == NULL)
37 return -1;
40 return 0;
43 void hb_ocl_close()
45 hb_opencl_library_close(&hb_ocl);
48 hb_opencl_library_t* hb_opencl_library_init()
50 hb_opencl_library_t *opencl;
51 if ((opencl = calloc(1, sizeof(hb_opencl_library_t))) == NULL)
53 hb_error("hb_opencl_library_init: memory allocation failure");
54 goto fail;
57 opencl->library = HB_OCL_DLOPEN;
58 if (opencl->library == NULL)
60 goto fail;
63 #define HB_OCL_LOAD(func) \
64 { \
65 if ((opencl->func = (void*)HB_OCL_DLSYM(opencl->library, #func)) == NULL) \
66 { \
67 hb_log("hb_opencl_library_init: failed to load function '%s'", #func); \
68 goto fail; \
69 } \
71 HB_OCL_LOAD(clBuildProgram);
72 HB_OCL_LOAD(clCreateBuffer);
73 HB_OCL_LOAD(clCreateCommandQueue);
74 HB_OCL_LOAD(clCreateContextFromType);
75 HB_OCL_LOAD(clCreateKernel);
76 HB_OCL_LOAD(clCreateProgramWithBinary);
77 HB_OCL_LOAD(clCreateProgramWithSource);
78 HB_OCL_LOAD(clEnqueueCopyBuffer);
79 HB_OCL_LOAD(clEnqueueMapBuffer);
80 HB_OCL_LOAD(clEnqueueNDRangeKernel);
81 HB_OCL_LOAD(clEnqueueReadBuffer);
82 HB_OCL_LOAD(clEnqueueUnmapMemObject);
83 HB_OCL_LOAD(clEnqueueWriteBuffer);
84 HB_OCL_LOAD(clFlush);
85 HB_OCL_LOAD(clGetCommandQueueInfo);
86 HB_OCL_LOAD(clGetContextInfo);
87 HB_OCL_LOAD(clGetDeviceIDs);
88 HB_OCL_LOAD(clGetDeviceInfo);
89 HB_OCL_LOAD(clGetPlatformIDs);
90 HB_OCL_LOAD(clGetPlatformInfo);
91 HB_OCL_LOAD(clGetProgramBuildInfo);
92 HB_OCL_LOAD(clGetProgramInfo);
93 HB_OCL_LOAD(clReleaseCommandQueue);
94 HB_OCL_LOAD(clReleaseContext);
95 HB_OCL_LOAD(clReleaseEvent);
96 HB_OCL_LOAD(clReleaseKernel);
97 HB_OCL_LOAD(clReleaseMemObject);
98 HB_OCL_LOAD(clReleaseProgram);
99 HB_OCL_LOAD(clSetKernelArg);
100 HB_OCL_LOAD(clWaitForEvents);
102 //success
103 return opencl;
105 fail:
106 hb_opencl_library_close(&opencl);
107 return NULL;
110 void hb_opencl_library_close(hb_opencl_library_t **_opencl)
112 if (_opencl == NULL)
114 return;
116 hb_opencl_library_t *opencl = *_opencl;
118 if (opencl != NULL)
120 if (opencl->library != NULL)
122 HB_OCL_DLCLOSE(opencl->library);
124 free(opencl);
126 *_opencl = NULL;
129 static int hb_opencl_device_is_supported(hb_opencl_device_t* device)
131 // we only support OpenCL on GPUs for now
132 // Ivy Bridge supports OpenCL on GPU, but it's too slow to be usable
133 // FIXME: disable on NVIDIA to to a bug
134 if ((device != NULL) &&
135 (device->type & CL_DEVICE_TYPE_GPU) &&
136 (device->ocl_vendor != HB_OCL_VENDOR_NVIDIA) &&
137 (device->ocl_vendor != HB_OCL_VENDOR_INTEL ||
138 hb_get_cpu_platform() != HB_CPU_PLATFORM_INTEL_IVB))
140 int major, minor;
141 // check OpenCL version:
142 // OpenCL<space><major_version.minor_version><space><vendor-specific information>
143 if (sscanf(device->version, "OpenCL %d.%d", &major, &minor) != 2)
145 return 0;
147 return (major > HB_OCL_MINVERSION_MAJOR) || (major == HB_OCL_MINVERSION_MAJOR &&
148 minor >= HB_OCL_MINVERSION_MINOR);
150 return 0;
153 static hb_opencl_device_t* hb_opencl_device_get(hb_opencl_library_t *opencl,
154 cl_device_id device_id)
156 if (opencl == NULL || opencl->clGetDeviceInfo == NULL)
158 hb_error("hb_opencl_device_get: OpenCL support not available");
159 return NULL;
161 else if (device_id == NULL)
163 hb_error("hb_opencl_device_get: invalid device ID");
164 return NULL;
167 hb_opencl_device_t *device = calloc(1, sizeof(hb_opencl_device_t));
168 if (device == NULL)
170 hb_error("hb_opencl_device_get: memory allocation failure");
171 return NULL;
174 cl_int status = CL_SUCCESS;
175 device->id = device_id;
177 status |= opencl->clGetDeviceInfo(device->id, CL_DEVICE_VENDOR, sizeof(device->vendor),
178 device->vendor, NULL);
179 status |= opencl->clGetDeviceInfo(device->id, CL_DEVICE_NAME, sizeof(device->name),
180 device->name, NULL);
181 status |= opencl->clGetDeviceInfo(device->id, CL_DEVICE_VERSION, sizeof(device->version),
182 device->version, NULL);
183 status |= opencl->clGetDeviceInfo(device->id, CL_DEVICE_TYPE, sizeof(device->type),
184 &device->type, NULL);
185 status |= opencl->clGetDeviceInfo(device->id, CL_DEVICE_PLATFORM, sizeof(device->platform),
186 &device->platform, NULL);
187 status |= opencl->clGetDeviceInfo(device->id, CL_DRIVER_VERSION, sizeof(device->driver),
188 device->driver, NULL);
189 if (status != CL_SUCCESS)
191 free(device);
192 return NULL;
195 if (!strcmp(device->vendor, "Advanced Micro Devices, Inc.") ||
196 !strcmp(device->vendor, "AMD"))
198 device->ocl_vendor = HB_OCL_VENDOR_AMD;
200 else if (!strncmp(device->vendor, "NVIDIA", 6 /* strlen("NVIDIA") */))
202 device->ocl_vendor = HB_OCL_VENDOR_NVIDIA;
204 else if (!strncmp(device->vendor, "Intel", 5 /* strlen("Intel") */))
206 device->ocl_vendor = HB_OCL_VENDOR_INTEL;
208 else
210 device->ocl_vendor = HB_OCL_VENDOR_OTHER;
213 return device;
216 static void hb_opencl_devices_list_close(hb_list_t **_list)
218 if (_list != NULL)
220 hb_list_t *list = *_list;
221 hb_opencl_device_t *device;
222 while (list != NULL && hb_list_count(list) > 0)
224 if ((device = hb_list_item(list, 0)) != NULL)
226 hb_list_rem(list, device);
227 free(device);
231 hb_list_close(_list);
234 static hb_list_t* hb_opencl_devices_list_get(hb_opencl_library_t *opencl,
235 cl_device_type device_type)
237 if (opencl == NULL ||
238 opencl->library == NULL ||
239 opencl->clGetDeviceIDs == NULL ||
240 opencl->clGetDeviceInfo == NULL ||
241 opencl->clGetPlatformIDs == NULL)
243 hb_error("hb_opencl_devices_list_get: OpenCL support not available");
244 return NULL;
247 hb_list_t *list = hb_list_init();
248 if (list == NULL)
250 hb_error("hb_opencl_devices_list_get: memory allocation failure");
251 return NULL;
254 cl_device_id *device_ids = NULL;
255 hb_opencl_device_t *device = NULL;
256 cl_platform_id *platform_ids = NULL;
257 cl_uint i, j, num_platforms, num_devices;
259 if (opencl->clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS || !num_platforms)
261 goto fail;
263 if ((platform_ids = malloc(sizeof(cl_platform_id) * num_platforms)) == NULL)
265 hb_error("hb_opencl_devices_list_get: memory allocation failure");
266 goto fail;
268 if (opencl->clGetPlatformIDs(num_platforms, platform_ids, NULL) != CL_SUCCESS)
270 goto fail;
272 for (i = 0; i < num_platforms; i++)
274 if (opencl->clGetDeviceIDs(platform_ids[i], device_type, 0, NULL, &num_devices) != CL_SUCCESS || !num_devices)
276 // non-fatal
277 continue;
279 if ((device_ids = malloc(sizeof(cl_device_id) * num_devices)) == NULL)
281 hb_error("hb_opencl_devices_list_get: memory allocation failure");
282 goto fail;
284 if (opencl->clGetDeviceIDs(platform_ids[i], device_type, num_devices, device_ids, NULL) != CL_SUCCESS)
286 // non-fatal
287 continue;
289 for (j = 0; j < num_devices; j++)
291 if ((device = hb_opencl_device_get(opencl, device_ids[j])) != NULL)
293 hb_list_add(list, device);
298 goto end;
300 fail:
301 hb_opencl_devices_list_close(&list);
303 end:
304 free(platform_ids);
305 free(device_ids);
306 return list;
309 int hb_opencl_available()
311 static int opencl_available = -1;
312 if (opencl_available >= 0)
314 return opencl_available;
316 opencl_available = 0;
319 * Check whether we can load the OpenCL library, then check devices and make
320 * sure we support running OpenCL code on at least one of them.
322 hb_opencl_library_t *opencl;
323 if ((opencl = hb_opencl_library_init()) != NULL)
325 int i;
326 hb_list_t *device_list;
327 hb_opencl_device_t *device;
328 if ((device_list = hb_opencl_devices_list_get(opencl, CL_DEVICE_TYPE_ALL)) != NULL)
330 for (i = 0; i < hb_list_count(device_list); i++)
332 if ((device = hb_list_item(device_list, i)) != NULL &&
333 (hb_opencl_device_is_supported(device)))
335 opencl_available = 1;
336 break;
339 hb_opencl_devices_list_close(&device_list);
341 hb_opencl_library_close(&opencl);
343 return opencl_available;
346 void hb_opencl_info_print()
349 * Note: this function should not log any warnings or errors.
350 * Its only purpose is to list OpenCL-capable devices, so let's initialize
351 * only what we absolutely need here, rather than calling library_open().
353 hb_opencl_library_t ocl, *opencl = &ocl;
354 if ((opencl->library = (void*)HB_OCL_DLOPEN) == NULL ||
355 (opencl->clGetDeviceIDs = (void*)HB_OCL_DLSYM(opencl->library, "clGetDeviceIDs" )) == NULL ||
356 (opencl->clGetDeviceInfo = (void*)HB_OCL_DLSYM(opencl->library, "clGetDeviceInfo" )) == NULL ||
357 (opencl->clGetPlatformIDs = (void*)HB_OCL_DLSYM(opencl->library, "clGetPlatformIDs")) == NULL)
359 // zero or insufficient OpenCL support
360 hb_log("OpenCL: library not available");
361 goto end;
364 int i, idx;
365 hb_list_t *device_list;
366 hb_opencl_device_t *device;
367 if ((device_list = hb_opencl_devices_list_get(opencl, CL_DEVICE_TYPE_ALL)) != NULL)
369 for (i = 0, idx = 1; i < hb_list_count(device_list); i++)
371 if ((device = hb_list_item(device_list, i)) != NULL)
373 // don't list CPU devices (always unsupported)
374 if (!(device->type & CL_DEVICE_TYPE_CPU))
376 hb_log("OpenCL device #%d: %s %s", idx++, device->vendor, device->name);
377 hb_log(" - OpenCL version: %s", device->version + 7 /* strlen("OpenCL ") */);
378 hb_log(" - driver version: %s", device->driver);
379 hb_log(" - device type: %s%s",
380 device->type & CL_DEVICE_TYPE_CPU ? "CPU" :
381 device->type & CL_DEVICE_TYPE_GPU ? "GPU" :
382 device->type & CL_DEVICE_TYPE_CUSTOM ? "Custom" :
383 device->type & CL_DEVICE_TYPE_ACCELERATOR ? "Accelerator" : "Unknown",
384 device->type & CL_DEVICE_TYPE_DEFAULT ? " (default)" : "");
385 hb_log(" - supported: %s",
386 hb_opencl_device_is_supported(device) ? "YES" : "no");
390 hb_opencl_devices_list_close(&device_list);
393 end:
395 * Close only the initialized part
397 if (opencl->library != NULL)
399 HB_OCL_DLCLOSE(opencl->library);