FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
opencl.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
3  * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
4  * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com>
5  * Copyright (C) 2013 Lenny Wang <lwanghpc@gmail.com>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include "opencl.h"
25 #include "avstring.h"
26 #include "log.h"
27 #include "avassert.h"
28 #include "opt.h"
29 
30 #if HAVE_THREADS
31 #include "thread.h"
32 #include "atomic.h"
33 
34 static pthread_mutex_t * volatile atomic_opencl_lock = NULL;
35 #define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock)
36 #define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock)
37 #else
38 #define LOCK_OPENCL
39 #define UNLOCK_OPENCL
40 #endif
41 
42 #define MAX_KERNEL_CODE_NUM 200
43 
44 typedef struct {
46  const char *kernel_string;
47 } KernelCode;
48 
49 typedef struct {
50  const AVClass *class;
52  void *log_ctx;
55  /**
56  * if set to 1, the OpenCL environment was created by the user and
57  * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
58  */
62  cl_platform_id platform_id;
63  cl_device_type device_type;
64  cl_context context;
65  cl_device_id device_id;
66  cl_command_queue command_queue;
71 
72 #define OFFSET(x) offsetof(OpenclContext, x)
73 
74 static const AVOption opencl_options[] = {
75  { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
76  { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
77  { NULL }
78 };
79 
80 static const AVClass openclutils_class = {
81  .class_name = "opencl",
82  .option = opencl_options,
83  .item_name = av_default_item_name,
84  .version = LIBAVUTIL_VERSION_INT,
85  .log_level_offset_offset = offsetof(OpenclContext, log_offset),
86  .parent_log_context_offset = offsetof(OpenclContext, log_ctx),
87 };
88 
89 static OpenclContext opencl_ctx = {&openclutils_class};
90 
91 static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU};
92 
93 typedef struct {
94  int err_code;
95  const char *err_str;
97 
98 static const OpenclErrorMsg opencl_err_msg[] = {
99  {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"},
100  {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"},
101  {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"},
102  {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"},
103  {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"},
104  {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"},
105  {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"},
106  {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"},
107  {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"},
108  {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"},
109  {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"},
110  {CL_MAP_FAILURE, "MAP FAILURE"},
111  {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"},
112  {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
113  {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"},
114  {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"},
115  {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"},
116  {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"},
117  {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"},
118  {CL_INVALID_VALUE, "INVALID VALUE"},
119  {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"},
120  {CL_INVALID_PLATFORM, "INVALID PLATFORM"},
121  {CL_INVALID_DEVICE, "INVALID DEVICE"},
122  {CL_INVALID_CONTEXT, "INVALID CONTEXT"},
123  {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"},
124  {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"},
125  {CL_INVALID_HOST_PTR, "INVALID HOST PTR"},
126  {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"},
127  {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"},
128  {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"},
129  {CL_INVALID_SAMPLER, "INVALID SAMPLER"},
130  {CL_INVALID_BINARY, "INVALID BINARY"},
131  {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"},
132  {CL_INVALID_PROGRAM, "INVALID PROGRAM"},
133  {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"},
134  {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"},
135  {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"},
136  {CL_INVALID_KERNEL, "INVALID KERNEL"},
137  {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"},
138  {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"},
139  {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"},
140  {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"},
141  {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"},
142  {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"},
143  {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"},
144  {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"},
145  {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"},
146  {CL_INVALID_EVENT, "INVALID EVENT"},
147  {CL_INVALID_OPERATION, "INVALID OPERATION"},
148  {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"},
149  {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"},
150  {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"},
151  {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"},
152  {CL_INVALID_PROPERTY, "INVALID PROPERTY"},
153  {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"},
154  {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"},
155  {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"},
156  {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"},
157 };
158 
159 const char *av_opencl_errstr(cl_int status)
160 {
161  int i;
162  for (i = 0; i < FF_ARRAY_ELEMS(opencl_err_msg); i++) {
163  if (opencl_err_msg[i].err_code == status)
164  return opencl_err_msg[i].err_str;
165  }
166  return "unknown error";
167 }
168 
169 static void free_device_list(AVOpenCLDeviceList *device_list)
170 {
171  int i, j;
172  if (!device_list)
173  return;
174  for (i = 0; i < device_list->platform_num; i++) {
175  if (!device_list->platform_node[i])
176  continue;
177  for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
178  av_freep(&(device_list->platform_node[i]->device_node[j]->device_name));
179  av_freep(&(device_list->platform_node[i]->device_node[j]));
180  }
181  av_freep(&device_list->platform_node[i]->device_node);
182  av_freep(&(device_list->platform_node[i]->platform_name));
183  av_freep(&device_list->platform_node[i]);
184  }
185  av_freep(&device_list->platform_node);
186  device_list->platform_num = 0;
187 }
188 
189 static int get_device_list(AVOpenCLDeviceList *device_list)
190 {
191  cl_int status;
192  int i, j, k, device_num, total_devices_num, ret = 0;
193  int *devices_num;
194  cl_platform_id *platform_ids = NULL;
195  cl_device_id *device_ids = NULL;
196  AVOpenCLDeviceNode *device_node = NULL;
197  size_t platform_name_size = 0;
198  size_t device_name_size = 0;
199  status = clGetPlatformIDs(0, NULL, &device_list->platform_num);
200  if (status != CL_SUCCESS) {
201  av_log(&opencl_ctx, AV_LOG_ERROR,
202  "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
203  return AVERROR_EXTERNAL;
204  }
205  platform_ids = av_mallocz_array(device_list->platform_num, sizeof(cl_platform_id));
206  if (!platform_ids)
207  return AVERROR(ENOMEM);
208  status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL);
209  if (status != CL_SUCCESS) {
210  av_log(&opencl_ctx, AV_LOG_ERROR,
211  "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
212  ret = AVERROR_EXTERNAL;
213  goto end;
214  }
215  device_list->platform_node = av_mallocz_array(device_list->platform_num, sizeof(AVOpenCLPlatformNode *));
216  if (!device_list->platform_node) {
217  ret = AVERROR(ENOMEM);
218  goto end;
219  }
220  devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type));
221  if (!devices_num) {
222  ret = AVERROR(ENOMEM);
223  goto end;
224  }
225  for (i = 0; i < device_list->platform_num; i++) {
226  device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode));
227  if (!device_list->platform_node[i]) {
228  ret = AVERROR(ENOMEM);
229  goto end;
230  }
231  device_list->platform_node[i]->platform_id = platform_ids[i];
232  status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
233  0, NULL, &platform_name_size);
234  if (status != CL_SUCCESS) {
235  av_log(&opencl_ctx, AV_LOG_WARNING,
236  "Could not get size of platform name: %s\n", av_opencl_errstr(status));
237  } else {
238  device_list->platform_node[i]->platform_name = av_malloc(platform_name_size * sizeof(char));
239  if (!device_list->platform_node[i]->platform_name) {
240  av_log(&opencl_ctx, AV_LOG_WARNING,
241  "Could not allocate memory for device name: %s\n", av_opencl_errstr(status));
242  } else {
243  status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
244  platform_name_size * sizeof(char),
245  device_list->platform_node[i]->platform_name, NULL);
246  if (status != CL_SUCCESS) {
247  av_log(&opencl_ctx, AV_LOG_WARNING,
248  "Could not get platform name: %s\n", av_opencl_errstr(status));
249  }
250  }
251  }
252  total_devices_num = 0;
253  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
254  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id,
255  device_type[j], 0, NULL, &devices_num[j]);
256  total_devices_num += devices_num[j];
257  }
258  device_list->platform_node[i]->device_node = av_mallocz_array(total_devices_num, sizeof(AVOpenCLDeviceNode *));
259  if (!device_list->platform_node[i]->device_node) {
260  ret = AVERROR(ENOMEM);
261  goto end;
262  }
263  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
264  if (devices_num[j]) {
265  device_ids = av_mallocz_array(devices_num[j], sizeof(cl_device_id));
266  if (!device_ids) {
267  ret = AVERROR(ENOMEM);
268  goto end;
269  }
270  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j],
271  devices_num[j], device_ids, NULL);
272  if (status != CL_SUCCESS) {
273  av_log(&opencl_ctx, AV_LOG_WARNING,
274  "Could not get device ID: %s:\n", av_opencl_errstr(status));
275  av_freep(&device_ids);
276  continue;
277  }
278  for (k = 0; k < devices_num[j]; k++) {
279  device_num = device_list->platform_node[i]->device_num;
280  device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode));
281  if (!device_list->platform_node[i]->device_node[device_num]) {
282  ret = AVERROR(ENOMEM);
283  goto end;
284  }
285  device_node = device_list->platform_node[i]->device_node[device_num];
286  device_node->device_id = device_ids[k];
287  device_node->device_type = device_type[j];
288  status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
289  0, NULL, &device_name_size);
290  if (status != CL_SUCCESS) {
291  av_log(&opencl_ctx, AV_LOG_WARNING,
292  "Could not get size of device name: %s\n", av_opencl_errstr(status));
293  continue;
294  }
295  device_node->device_name = av_malloc(device_name_size * sizeof(char));
296  if (!device_node->device_name) {
297  av_log(&opencl_ctx, AV_LOG_WARNING,
298  "Could not allocate memory for device name: %s\n", av_opencl_errstr(status));
299  continue;
300  }
301  status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
302  device_name_size * sizeof(char),
303  device_node->device_name, NULL);
304  if (status != CL_SUCCESS) {
305  av_log(&opencl_ctx, AV_LOG_WARNING,
306  "Could not get device name: %s\n", av_opencl_errstr(status));
307  continue;
308  }
309  device_list->platform_node[i]->device_num++;
310  }
311  av_freep(&device_ids);
312  }
313  }
314  }
315 end:
316  av_freep(&platform_ids);
317  av_freep(&devices_num);
318  av_freep(&device_ids);
319  if (ret < 0)
320  free_device_list(device_list);
321  return ret;
322 }
323 
325 {
326  int ret = 0;
327  *device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
328  if (!(*device_list)) {
329  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n");
330  return AVERROR(ENOMEM);
331  }
332  ret = get_device_list(*device_list);
333  if (ret < 0) {
334  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n");
335  free_device_list(*device_list);
336  av_freep(device_list);
337  return ret;
338  }
339  return ret;
340 }
341 
343 {
344  free_device_list(*device_list);
345  av_freep(device_list);
346 }
347 
348 static inline int init_opencl_mtx(void)
349 {
350 #if HAVE_THREADS
351  if (!atomic_opencl_lock) {
352  int err;
354  if (!tmp)
355  return AVERROR(ENOMEM);
356  if ((err = pthread_mutex_init(tmp, NULL))) {
357  av_free(tmp);
358  return AVERROR(err);
359  }
360  if (avpriv_atomic_ptr_cas((void * volatile *)&atomic_opencl_lock, NULL, tmp)) {
362  av_free(tmp);
363  }
364  }
365 #endif
366  return 0;
367 }
368 
369 int av_opencl_set_option(const char *key, const char *val)
370 {
371  int ret = init_opencl_mtx( );
372  if (ret < 0)
373  return ret;
374  LOCK_OPENCL;
375  if (!opencl_ctx.opt_init_flag) {
376  av_opt_set_defaults(&opencl_ctx);
377  opencl_ctx.opt_init_flag = 1;
378  }
379  ret = av_opt_set(&opencl_ctx, key, val, 0);
381  return ret;
382 }
383 
384 int av_opencl_get_option(const char *key, uint8_t **out_val)
385 {
386  int ret = 0;
387  LOCK_OPENCL;
388  ret = av_opt_get(&opencl_ctx, key, 0, out_val);
390  return ret;
391 }
392 
394 {
395  /*FIXME: free openclutils context*/
396  LOCK_OPENCL;
397  av_opt_free(&opencl_ctx);
399 }
400 
402 {
404  if (!ext) {
405  av_log(&opencl_ctx, AV_LOG_ERROR,
406  "Could not malloc external opencl environment data space\n");
407  }
408  return ext;
409 }
410 
412 {
413  av_freep(ext_opencl_env);
414 }
415 
416 int av_opencl_register_kernel_code(const char *kernel_code)
417 {
418  int i, ret = init_opencl_mtx( );
419  if (ret < 0)
420  return ret;
421  LOCK_OPENCL;
422  if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) {
423  av_log(&opencl_ctx, AV_LOG_ERROR,
424  "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
426  ret = AVERROR(EINVAL);
427  goto end;
428  }
429  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
430  if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) {
431  av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n");
432  goto end;
433  }
434  }
435  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code;
436  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0;
437  opencl_ctx.kernel_code_count++;
438 end:
440  return ret;
441 }
442 
443 cl_program av_opencl_compile(const char *program_name, const char *build_opts)
444 {
445  int i;
446  cl_int status, build_status;
447  int kernel_code_idx = 0;
448  const char *kernel_source = NULL;
449  size_t kernel_code_len;
450  char* ptr = NULL;
451  cl_program program = NULL;
452  size_t log_size;
453  char *log = NULL;
454 
455  LOCK_OPENCL;
456  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
457  // identify a program using a unique name within the kernel source
458  ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name);
459  if (ptr && !opencl_ctx.kernel_code[i].is_compiled) {
460  kernel_source = opencl_ctx.kernel_code[i].kernel_string;
461  kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string);
462  kernel_code_idx = i;
463  break;
464  }
465  }
466  if (!kernel_source) {
467  av_log(&opencl_ctx, AV_LOG_ERROR,
468  "Unable to find OpenCL kernel source '%s'\n", program_name);
469  goto end;
470  }
471 
472  /* create a CL program from kernel source */
473  program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status);
474  if(status != CL_SUCCESS) {
475  av_log(&opencl_ctx, AV_LOG_ERROR,
476  "Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status));
477  program = NULL;
478  goto end;
479  }
480 
481  build_status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL);
482  status = clGetProgramBuildInfo(program, opencl_ctx.device_id,
483  CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
484  if (status != CL_SUCCESS) {
485  av_log(&opencl_ctx, AV_LOG_WARNING,
486  "Failed to get compilation log: %s\n",
487  av_opencl_errstr(status));
488  } else {
489  log = av_malloc(log_size);
490  if (log) {
491  status = clGetProgramBuildInfo(program, opencl_ctx.device_id,
492  CL_PROGRAM_BUILD_LOG, log_size,
493  log, NULL);
494  if (status != CL_SUCCESS) {
495  av_log(&opencl_ctx, AV_LOG_WARNING,
496  "Failed to get compilation log: %s\n",
497  av_opencl_errstr(status));
498  } else {
499  int level = build_status == CL_SUCCESS ? AV_LOG_DEBUG :
500  AV_LOG_ERROR;
501  av_log(&opencl_ctx, level, "Compilation log:\n%s\n", log);
502  }
503  }
504  av_freep(&log);
505  }
506  if (build_status != CL_SUCCESS) {
507  av_log(&opencl_ctx, AV_LOG_ERROR,
508  "Compilation failed with OpenCL program '%s': %s\n",
509  program_name, av_opencl_errstr(build_status));
510  program = NULL;
511  goto end;
512  }
513 
514  opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1;
515 end:
517  return program;
518 }
519 
520 cl_command_queue av_opencl_get_command_queue(void)
521 {
522  return opencl_ctx.command_queue;
523 }
524 
525 static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
526 {
527  cl_int status;
528  cl_context_properties cps[3];
529  int i, ret = 0;
530  AVOpenCLDeviceNode *device_node = NULL;
531 
532  if (ext_opencl_env) {
533  if (opencl_ctx->is_user_created)
534  return 0;
535  opencl_ctx->platform_id = ext_opencl_env->platform_id;
536  opencl_ctx->is_user_created = 1;
537  opencl_ctx->command_queue = ext_opencl_env->command_queue;
538  opencl_ctx->context = ext_opencl_env->context;
539  opencl_ctx->device_id = ext_opencl_env->device_id;
540  opencl_ctx->device_type = ext_opencl_env->device_type;
541  } else {
542  if (!opencl_ctx->is_user_created) {
543  if (!opencl_ctx->device_list.platform_num) {
544  ret = get_device_list(&opencl_ctx->device_list);
545  if (ret < 0) {
546  return ret;
547  }
548  }
549  if (opencl_ctx->platform_idx >= 0) {
550  if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) {
551  av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n");
552  return AVERROR(EINVAL);
553  }
554  if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) {
555  av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n",
556  opencl_ctx->platform_idx);
557  return AVERROR(EINVAL);
558  }
559  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id;
560  } else {
561  /* get a usable platform by default*/
562  for (i = 0; i < opencl_ctx->device_list.platform_num; i++) {
563  if (opencl_ctx->device_list.platform_node[i]->device_num) {
564  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id;
565  opencl_ctx->platform_idx = i;
566  break;
567  }
568  }
569  }
570  if (!opencl_ctx->platform_id) {
571  av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n");
572  return AVERROR_EXTERNAL;
573  }
574  /* get a usable device*/
575  if (opencl_ctx->device_idx >= 0) {
576  if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) {
577  av_log(opencl_ctx, AV_LOG_ERROR,
578  "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx);
579  return AVERROR(EINVAL);
580  }
581  } else {
582  opencl_ctx->device_idx = 0;
583  }
584 
585  device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx];
586  opencl_ctx->device_id = device_node->device_id;
587  opencl_ctx->device_type = device_node->device_type;
588 
589  /*
590  * Use available platform.
591  */
592  av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, Device Name: %s\n",
593  opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
594  device_node->device_name);
595  cps[0] = CL_CONTEXT_PLATFORM;
596  cps[1] = (cl_context_properties)opencl_ctx->platform_id;
597  cps[2] = 0;
598 
599  opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type,
600  NULL, NULL, &status);
601  if (status != CL_SUCCESS) {
602  av_log(opencl_ctx, AV_LOG_ERROR,
603  "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status));
604  return AVERROR_EXTERNAL;
605  }
606  opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id,
607  0, &status);
608  if (status != CL_SUCCESS) {
609  av_log(opencl_ctx, AV_LOG_ERROR,
610  "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status));
611  return AVERROR_EXTERNAL;
612  }
613  }
614  }
615  return ret;
616 }
617 
619 {
620  int ret = init_opencl_mtx( );
621  if (ret < 0)
622  return ret;
623  LOCK_OPENCL;
624  if (!opencl_ctx.init_count) {
625  if (!opencl_ctx.opt_init_flag) {
626  av_opt_set_defaults(&opencl_ctx);
627  opencl_ctx.opt_init_flag = 1;
628  }
629  ret = init_opencl_env(&opencl_ctx, ext_opencl_env);
630  if (ret < 0)
631  goto end;
632  if (opencl_ctx.kernel_code_count <= 0) {
633  av_log(&opencl_ctx, AV_LOG_ERROR,
634  "No kernel code is registered, compile kernel file failed\n");
635  ret = AVERROR(EINVAL);
636  goto end;
637  }
638  }
639  opencl_ctx.init_count++;
640 end:
642  return ret;
643 }
644 
646 {
647  int i;
648  cl_int status;
649  LOCK_OPENCL;
650  opencl_ctx.init_count--;
651  if (opencl_ctx.is_user_created)
652  goto end;
653  if (opencl_ctx.init_count > 0)
654  goto end;
655  if (opencl_ctx.command_queue) {
656  status = clReleaseCommandQueue(opencl_ctx.command_queue);
657  if (status != CL_SUCCESS) {
658  av_log(&opencl_ctx, AV_LOG_ERROR,
659  "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status));
660  }
661  opencl_ctx.command_queue = NULL;
662  }
663  if (opencl_ctx.context) {
664  status = clReleaseContext(opencl_ctx.context);
665  if (status != CL_SUCCESS) {
666  av_log(&opencl_ctx, AV_LOG_ERROR,
667  "Could not release OpenCL context: %s\n", av_opencl_errstr(status));
668  }
669  opencl_ctx.context = NULL;
670  }
671  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
672  opencl_ctx.kernel_code[i].is_compiled = 0;
673  }
674  free_device_list(&opencl_ctx.device_list);
675 end:
676  if (opencl_ctx.init_count <= 0)
677  av_opt_free(&opencl_ctx); //FIXME: free openclutils context
679 }
680 
681 int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
682 {
683  cl_int status;
684  *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status);
685  if (status != CL_SUCCESS) {
686  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status));
687  return AVERROR_EXTERNAL;
688  }
689  return 0;
690 }
691 
692 void av_opencl_buffer_release(cl_mem *cl_buf)
693 {
694  cl_int status = 0;
695  if (!cl_buf)
696  return;
697  status = clReleaseMemObject(*cl_buf);
698  if (status != CL_SUCCESS) {
699  av_log(&opencl_ctx, AV_LOG_ERROR,
700  "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status));
701  }
702  memset(cl_buf, 0, sizeof(*cl_buf));
703 }
704 
705 int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
706 {
707  cl_int status;
708  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
709  CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size,
710  0, NULL, NULL, &status);
711 
712  if (status != CL_SUCCESS) {
713  av_log(&opencl_ctx, AV_LOG_ERROR,
714  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
715  return AVERROR_EXTERNAL;
716  }
717  memcpy(mapped, src_buf, buf_size);
718 
719  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
720  if (status != CL_SUCCESS) {
721  av_log(&opencl_ctx, AV_LOG_ERROR,
722  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
723  return AVERROR_EXTERNAL;
724  }
725  return 0;
726 }
727 
728 int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
729 {
730  cl_int status;
731  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
732  CL_TRUE, CL_MAP_READ, 0, buf_size,
733  0, NULL, NULL, &status);
734 
735  if (status != CL_SUCCESS) {
736  av_log(&opencl_ctx, AV_LOG_ERROR,
737  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
738  return AVERROR_EXTERNAL;
739  }
740  memcpy(dst_buf, mapped, buf_size);
741 
742  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
743  if (status != CL_SUCCESS) {
744  av_log(&opencl_ctx, AV_LOG_ERROR,
745  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
746  return AVERROR_EXTERNAL;
747  }
748  return 0;
749 }
750 
751 int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
752  uint8_t **src_data, int *plane_size, int plane_num)
753 {
754  int i, buffer_size = 0;
755  uint8_t *temp;
756  cl_int status;
757  void *mapped;
758  if ((unsigned int)plane_num > 8) {
759  return AVERROR(EINVAL);
760  }
761  for (i = 0;i < plane_num;i++) {
762  buffer_size += plane_size[i];
763  }
764  if (buffer_size > cl_buffer_size) {
765  av_log(&opencl_ctx, AV_LOG_ERROR,
766  "Cannot write image to OpenCL buffer: buffer too small\n");
767  return AVERROR(EINVAL);
768  }
769  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
770  CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
771  0, NULL, NULL, &status);
772  if (status != CL_SUCCESS) {
773  av_log(&opencl_ctx, AV_LOG_ERROR,
774  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
775  return AVERROR_EXTERNAL;
776  }
777  temp = mapped;
778  temp += dst_cl_offset;
779  for (i = 0; i < plane_num; i++) {
780  memcpy(temp, src_data[i], plane_size[i]);
781  temp += plane_size[i];
782  }
783  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
784  if (status != CL_SUCCESS) {
785  av_log(&opencl_ctx, AV_LOG_ERROR,
786  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
787  return AVERROR_EXTERNAL;
788  }
789  return 0;
790 }
791 
792 int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
793  cl_mem src_cl_buf, size_t cl_buffer_size)
794 {
795  int i,buffer_size = 0,ret = 0;
796  uint8_t *temp;
797  void *mapped;
798  cl_int status;
799  if ((unsigned int)plane_num > 8) {
800  return AVERROR(EINVAL);
801  }
802  for (i = 0; i < plane_num; i++) {
803  buffer_size += plane_size[i];
804  }
805  if (buffer_size > cl_buffer_size) {
806  av_log(&opencl_ctx, AV_LOG_ERROR,
807  "Cannot write image to CPU buffer: OpenCL buffer too small\n");
808  return AVERROR(EINVAL);
809  }
810  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
811  CL_TRUE, CL_MAP_READ, 0, buffer_size,
812  0, NULL, NULL, &status);
813 
814  if (status != CL_SUCCESS) {
815  av_log(&opencl_ctx, AV_LOG_ERROR,
816  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
817  return AVERROR_EXTERNAL;
818  }
819  temp = mapped;
820  if (ret >= 0) {
821  for (i = 0; i < plane_num; i++) {
822  memcpy(dst_data[i], temp, plane_size[i]);
823  temp += plane_size[i];
824  }
825  }
826  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
827  if (status != CL_SUCCESS) {
828  av_log(&opencl_ctx, AV_LOG_ERROR,
829  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
830  return AVERROR_EXTERNAL;
831  }
832  return 0;
833 }
834 
835 int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform,
836  int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env))
837 {
838  int64_t ret = 0;
839  cl_int status;
840  cl_context_properties cps[3];
841  AVOpenCLExternalEnv *ext_opencl_env = NULL;
842 
843  ext_opencl_env = av_opencl_alloc_external_env();
844  ext_opencl_env->device_id = device_node->device_id;
845  ext_opencl_env->device_type = device_node->device_type;
846  av_log(&opencl_ctx, AV_LOG_VERBOSE, "Performing test on OpenCL device %s\n",
847  device_node->device_name);
848 
849  cps[0] = CL_CONTEXT_PLATFORM;
850  cps[1] = (cl_context_properties)platform;
851  cps[2] = 0;
852  ext_opencl_env->context = clCreateContextFromType(cps, ext_opencl_env->device_type,
853  NULL, NULL, &status);
854  if (status != CL_SUCCESS || !ext_opencl_env->context) {
855  ret = AVERROR_EXTERNAL;
856  goto end;
857  }
858  ext_opencl_env->command_queue = clCreateCommandQueue(ext_opencl_env->context,
859  ext_opencl_env->device_id, 0, &status);
860  if (status != CL_SUCCESS || !ext_opencl_env->command_queue) {
861  ret = AVERROR_EXTERNAL;
862  goto end;
863  }
864  ret = benchmark(ext_opencl_env);
865  if (ret < 0)
866  av_log(&opencl_ctx, AV_LOG_ERROR, "Benchmark failed with OpenCL device %s\n",
867  device_node->device_name);
868 end:
869  if (ext_opencl_env->command_queue)
870  clReleaseCommandQueue(ext_opencl_env->command_queue);
871  if (ext_opencl_env->context)
872  clReleaseContext(ext_opencl_env->context);
873  av_opencl_free_external_env(&ext_opencl_env);
874  return ret;
875 }
#define NULL
Definition: coverity.c:32
const char const char void * val
Definition: avisynth_c.h:771
int init_count
Definition: opencl.c:53
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition: os2threads.h:106
AVOption.
Definition: opt.h:245
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
else temp
Definition: vf_mcdeint.c:259
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
Definition: avstring.c:56
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
Definition: opt.c:1264
KernelCode kernel_code[MAX_KERNEL_CODE_NUM]
Definition: opencl.c:68
void * log_ctx
Definition: opencl.c:52
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:252
#define LOCK_OPENCL
Definition: opencl.c:38
const char * av_opencl_errstr(cl_int status)
Get OpenCL error string.
Definition: opencl.c:159
int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
Read data from OpenCL buffer to memory buffer.
Definition: opencl.c:728
static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
Definition: opencl.c:525
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
HMTX pthread_mutex_t
Definition: os2threads.h:49
uint8_t
#define av_malloc(s)
AVOptions.
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
static const cl_device_type device_type[]
Definition: opencl.c:91
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
cl_platform_id platform_id
Definition: opencl.h:55
#define av_log(a,...)
int av_opencl_get_device_list(AVOpenCLDeviceList **device_list)
Get OpenCL device list.
Definition: opencl.c:324
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define avpriv_atomic_ptr_cas
Definition: atomic_gcc.h:60
av_default_item_name
#define MAX_KERNEL_CODE_NUM
Definition: opencl.c:42
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
static const OpenclErrorMsg opencl_err_msg[]
Definition: opencl.c:98
static int init_opencl_mtx(void)
Definition: opencl.c:348
int opt_init_flag
Definition: opencl.c:54
simple assert() macros that are a bit more flexible than ISO C assert().
cl_platform_id platform_id
Definition: opencl.c:62
cl_device_id device_id
Definition: opencl.h:51
char * platform_name
Definition: opencl.h:56
cl_device_id device_id
Definition: opencl.h:70
static void * av_mallocz_array(size_t nmemb, size_t size)
Definition: mem.h:226
AVOpenCLDeviceList device_list
Definition: opencl.c:69
AVOpenCLDeviceNode ** device_node
Definition: opencl.h:58
cl_platform_id platform_id
Definition: opencl.h:67
static const AVOption opencl_options[]
Definition: opencl.c:74
int is_compiled
Definition: opencl.c:45
static void free_device_list(AVOpenCLDeviceList *device_list)
Definition: opencl.c:169
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition: os2threads.h:98
cl_program av_opencl_compile(const char *program_name, const char *build_opts)
compile specific OpenCL kernel source
Definition: opencl.c:443
int av_opencl_set_option(const char *key, const char *val)
Set option in the global OpenCL context.
Definition: opencl.c:369
int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
Create OpenCL buffer.
Definition: opencl.c:681
#define FF_ARRAY_ELEMS(a)
int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, uint8_t **src_data, int *plane_size, int plane_num)
Write image data from memory to OpenCL buffer.
Definition: opencl.c:751
#define OFFSET(x)
Definition: opencl.c:72
static const AVClass openclutils_class
Definition: opencl.c:80
cl_device_type device_type
Definition: opencl.h:68
static OpenclContext opencl_ctx
Definition: opencl.c:89
AVOpenCLPlatformNode ** platform_node
Definition: opencl.h:63
int av_opencl_register_kernel_code(const char *kernel_code)
Register kernel code.
Definition: opencl.c:416
void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env)
Free OpenCL external environment.
Definition: opencl.c:411
Describe the class of an AVClass context structure.
Definition: log.h:67
void av_opencl_free_option(void)
Free option values of the global OpenCL context.
Definition: opencl.c:393
AVOpenCLExternalEnv * av_opencl_alloc_external_env(void)
Allocate OpenCL external environment.
Definition: opencl.c:401
void av_opencl_buffer_release(cl_mem *cl_buf)
Release OpenCL buffer.
Definition: opencl.c:692
cl_context context
Definition: opencl.c:64
cl_command_queue command_queue
Definition: opencl.h:71
static int get_device_list(AVOpenCLDeviceList *device_list)
Definition: opencl.c:189
int is_user_created
if set to 1, the OpenCL environment was created by the user and passed as AVOpenCLExternalEnv when in...
Definition: opencl.c:59
const char * kernel_string
Definition: opencl.c:46
char * device_name
Definition: opencl.h:50
cl_command_queue av_opencl_get_command_queue(void)
get OpenCL command queue
Definition: opencl.c:520
int err_code
Definition: opencl.c:94
static int flags
Definition: cpu.c:47
uint8_t level
Definition: svq3.c:207
void av_opt_free(void *obj)
Free all allocated objects in obj.
Definition: opt.c:1516
int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
Write OpenCL buffer with data from src_buf.
Definition: opencl.c:705
void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
Free OpenCL device list.
Definition: opencl.c:342
int platform_idx
Definition: opencl.c:60
void av_opencl_uninit(void)
Release OpenCL environment.
Definition: opencl.c:645
cl_device_id device_id
Definition: opencl.c:65
cl_context context
Definition: opencl.h:69
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:732
#define av_free(p)
int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform, int64_t(*benchmark)(AVOpenCLExternalEnv *ext_opencl_env))
Benchmark an OpenCL device with a user defined callback function.
Definition: opencl.c:835
static uint8_t tmp[8]
Definition: des.c:38
int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
Initialize the run time OpenCL environment.
Definition: opencl.c:618
int log_offset
Definition: opencl.c:51
cl_device_type device_type
Definition: opencl.c:63
OpenCL wrapper.
int av_opencl_get_option(const char *key, uint8_t **out_val)
Get option value from the global OpenCL context.
Definition: opencl.c:384
cl_command_queue command_queue
Definition: opencl.c:66
#define av_freep(p)
int kernel_code_count
Definition: opencl.c:67
const char * err_str
Definition: opencl.c:95
int device_idx
Definition: opencl.c:61
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:431
#define UNLOCK_OPENCL
Definition: opencl.c:39
const char program_name[]
program name, defined by the program for show_version().
Definition: ffmpeg.c:109
int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, cl_mem src_cl_buf, size_t cl_buffer_size)
Read image data from OpenCL buffer.
Definition: opencl.c:792