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_PTHREADS
31 
32 #include <pthread.h>
33 static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER;
34 
35 #define LOCK_OPENCL pthread_mutex_lock(&atomic_opencl_lock)
36 #define UNLOCK_OPENCL pthread_mutex_unlock(&atomic_opencl_lock)
37 
38 #elif !HAVE_THREADS
39 #define LOCK_OPENCL
40 #define UNLOCK_OPENCL
41 #endif
42 
43 #define MAX_KERNEL_CODE_NUM 200
44 
45 typedef struct {
47  const char *kernel_string;
48 } KernelCode;
49 
50 typedef struct {
51  const AVClass *class;
53  void *log_ctx;
56  /**
57  * if set to 1, the OpenCL environment was created by the user and
58  * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
59  */
63  cl_platform_id platform_id;
64  cl_device_type device_type;
65  cl_context context;
66  cl_device_id device_id;
67  cl_command_queue command_queue;
68 #if FF_API_OLD_OPENCL
71  cl_program programs[MAX_KERNEL_CODE_NUM];
73 #endif
78 
79 #define OFFSET(x) offsetof(OpenclContext, x)
80 
81 static const AVOption opencl_options[] = {
82  { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
83  { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
84 #if FF_API_OLD_OPENCL
85  { "build_options", "build options of opencl", OFFSET(build_options), AV_OPT_TYPE_STRING, {.str="-I."}, CHAR_MIN, CHAR_MAX},
86 #endif
87  { NULL }
88 };
89 
90 static const AVClass openclutils_class = {
91  .class_name = "OPENCLUTILS",
92  .option = opencl_options,
93  .item_name = av_default_item_name,
94  .version = LIBAVUTIL_VERSION_INT,
95  .log_level_offset_offset = offsetof(OpenclContext, log_offset),
96  .parent_log_context_offset = offsetof(OpenclContext, log_ctx),
97 };
98 
99 static OpenclContext opencl_ctx = {&openclutils_class};
100 
101 static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU};
102 
103 typedef struct {
104  int err_code;
105  const char *err_str;
107 
108 static const OpenclErrorMsg opencl_err_msg[] = {
109  {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"},
110  {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"},
111  {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"},
112  {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"},
113  {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"},
114  {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"},
115  {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"},
116  {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"},
117  {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"},
118  {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"},
119  {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"},
120  {CL_MAP_FAILURE, "MAP FAILURE"},
121  {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"},
122  {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
123  {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"},
124  {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"},
125  {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"},
126  {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"},
127  {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"},
128  {CL_INVALID_VALUE, "INVALID VALUE"},
129  {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"},
130  {CL_INVALID_PLATFORM, "INVALID PLATFORM"},
131  {CL_INVALID_DEVICE, "INVALID DEVICE"},
132  {CL_INVALID_CONTEXT, "INVALID CONTEXT"},
133  {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"},
134  {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"},
135  {CL_INVALID_HOST_PTR, "INVALID HOST PTR"},
136  {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"},
137  {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"},
138  {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"},
139  {CL_INVALID_SAMPLER, "INVALID SAMPLER"},
140  {CL_INVALID_BINARY, "INVALID BINARY"},
141  {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"},
142  {CL_INVALID_PROGRAM, "INVALID PROGRAM"},
143  {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"},
144  {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"},
145  {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"},
146  {CL_INVALID_KERNEL, "INVALID KERNEL"},
147  {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"},
148  {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"},
149  {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"},
150  {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"},
151  {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"},
152  {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"},
153  {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"},
154  {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"},
155  {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"},
156  {CL_INVALID_EVENT, "INVALID EVENT"},
157  {CL_INVALID_OPERATION, "INVALID OPERATION"},
158  {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"},
159  {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"},
160  {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"},
161  {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"},
162  {CL_INVALID_PROPERTY, "INVALID PROPERTY"},
163  {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"},
164  {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"},
165  {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"},
166  {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"},
167 };
168 
169 const char *av_opencl_errstr(cl_int status)
170 {
171  int i;
172  for (i = 0; i < sizeof(opencl_err_msg); i++) {
173  if (opencl_err_msg[i].err_code == status)
174  return opencl_err_msg[i].err_str;
175  }
176  return "unknown error";
177 }
178 
179 static void free_device_list(AVOpenCLDeviceList *device_list)
180 {
181  int i, j;
182  if (!device_list)
183  return;
184  for (i = 0; i < device_list->platform_num; i++) {
185  if (!device_list->platform_node[i])
186  continue;
187  for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
188  av_freep(&(device_list->platform_node[i]->device_node[j]));
189  }
190  av_freep(&device_list->platform_node[i]->device_node);
191  av_freep(&device_list->platform_node[i]);
192  }
193  av_freep(&device_list->platform_node);
194  device_list->platform_num = 0;
195 }
196 
197 static int get_device_list(AVOpenCLDeviceList *device_list)
198 {
199  cl_int status;
200  int i, j, k, device_num, total_devices_num, ret = 0;
201  int *devices_num;
202  cl_platform_id *platform_ids = NULL;
203  cl_device_id *device_ids = NULL;
204  AVOpenCLDeviceNode *device_node = NULL;
205  status = clGetPlatformIDs(0, NULL, &device_list->platform_num);
206  if (status != CL_SUCCESS) {
207  av_log(&opencl_ctx, AV_LOG_ERROR,
208  "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
209  return AVERROR_EXTERNAL;
210  }
211  platform_ids = av_mallocz(device_list->platform_num * sizeof(cl_platform_id));
212  if (!platform_ids)
213  return AVERROR(ENOMEM);
214  status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL);
215  if (status != CL_SUCCESS) {
216  av_log(&opencl_ctx, AV_LOG_ERROR,
217  "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
218  ret = AVERROR_EXTERNAL;
219  goto end;
220  }
221  device_list->platform_node = av_mallocz(device_list->platform_num * sizeof(AVOpenCLPlatformNode *));
222  if (!device_list->platform_node) {
223  ret = AVERROR(ENOMEM);
224  goto end;
225  }
226  devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type));
227  if (!devices_num) {
228  ret = AVERROR(ENOMEM);
229  goto end;
230  }
231  for (i = 0; i < device_list->platform_num; i++) {
232  device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode));
233  if (!device_list->platform_node[i]) {
234  ret = AVERROR(ENOMEM);
235  goto end;
236  }
237  device_list->platform_node[i]->platform_id = platform_ids[i];
238  status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
239  sizeof(device_list->platform_node[i]->platform_name),
240  device_list->platform_node[i]->platform_name, NULL);
241  total_devices_num = 0;
242  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
243  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id,
244  device_type[j], 0, NULL, &devices_num[j]);
245  total_devices_num += devices_num[j];
246  }
247  device_list->platform_node[i]->device_node = av_mallocz(total_devices_num * sizeof(AVOpenCLDeviceNode *));
248  if (!device_list->platform_node[i]->device_node) {
249  ret = AVERROR(ENOMEM);
250  goto end;
251  }
252  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
253  if (devices_num[j]) {
254  device_ids = av_mallocz(devices_num[j] * sizeof(cl_device_id));
255  if (!device_ids) {
256  ret = AVERROR(ENOMEM);
257  goto end;
258  }
259  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j],
260  devices_num[j], device_ids, NULL);
261  if (status != CL_SUCCESS) {
262  av_log(&opencl_ctx, AV_LOG_WARNING,
263  "Could not get device ID: %s:\n", av_opencl_errstr(status));
264  av_freep(&device_ids);
265  continue;
266  }
267  for (k = 0; k < devices_num[j]; k++) {
268  device_num = device_list->platform_node[i]->device_num;
269  device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode));
270  if (!device_list->platform_node[i]->device_node[device_num]) {
271  ret = AVERROR(ENOMEM);
272  goto end;
273  }
274  device_node = device_list->platform_node[i]->device_node[device_num];
275  device_node->device_id = device_ids[k];
276  device_node->device_type = device_type[j];
277  status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
278  sizeof(device_node->device_name), device_node->device_name,
279  NULL);
280  if (status != CL_SUCCESS) {
281  av_log(&opencl_ctx, AV_LOG_WARNING,
282  "Could not get device name: %s\n", av_opencl_errstr(status));
283  continue;
284  }
285  device_list->platform_node[i]->device_num++;
286  }
287  av_freep(&device_ids);
288  }
289  }
290  }
291 end:
292  av_freep(&platform_ids);
293  av_freep(&devices_num);
294  av_freep(&device_ids);
295  if (ret < 0)
296  free_device_list(device_list);
297  return ret;
298 }
299 
301 {
302  int ret = 0;
303  *device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
304  if (!(*device_list)) {
305  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n");
306  return AVERROR(ENOMEM);
307  }
308  ret = get_device_list(*device_list);
309  if (ret < 0) {
310  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n");
311  free_device_list(*device_list);
312  av_freep(device_list);
313  return ret;
314  }
315  return ret;
316 }
317 
319 {
320  free_device_list(*device_list);
321  av_freep(device_list);
322 }
323 
324 int av_opencl_set_option(const char *key, const char *val)
325 {
326  int ret = 0;
327  LOCK_OPENCL;
328  if (!opencl_ctx.opt_init_flag) {
329  av_opt_set_defaults(&opencl_ctx);
330  opencl_ctx.opt_init_flag = 1;
331  }
332  ret = av_opt_set(&opencl_ctx, key, val, 0);
334  return ret;
335 }
336 
337 int av_opencl_get_option(const char *key, uint8_t **out_val)
338 {
339  int ret = 0;
340  LOCK_OPENCL;
341  ret = av_opt_get(&opencl_ctx, key, 0, out_val);
343  return ret;
344 }
345 
347 {
348  /*FIXME: free openclutils context*/
349  LOCK_OPENCL;
350  av_opt_free(&opencl_ctx);
352 }
353 
355 {
357  if (!ext) {
358  av_log(&opencl_ctx, AV_LOG_ERROR,
359  "Could not malloc external opencl environment data space\n");
360  }
361  return ext;
362 }
363 
365 {
366  av_freep(ext_opencl_env);
367 }
368 
369 int av_opencl_register_kernel_code(const char *kernel_code)
370 {
371  int i, ret = 0;
372  LOCK_OPENCL;
373  if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) {
374  av_log(&opencl_ctx, AV_LOG_ERROR,
375  "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
377  ret = AVERROR(EINVAL);
378  goto end;
379  }
380  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
381  if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) {
382  av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n");
383  goto end;
384  }
385  }
386  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code;
387  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0;
388  opencl_ctx.kernel_code_count++;
389 end:
391  return ret;
392 }
393 
394 cl_program av_opencl_compile(const char *program_name, const char *build_opts)
395 {
396  int i;
397  cl_int status;
398  int kernel_code_idx = 0;
399  const char *kernel_source;
400  size_t kernel_code_len;
401  char* ptr = NULL;
402  cl_program program = NULL;
403 
404  LOCK_OPENCL;
405  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
406  // identify a program using a unique name within the kernel source
407  ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name);
408  if (ptr && !opencl_ctx.kernel_code[i].is_compiled) {
409  kernel_source = opencl_ctx.kernel_code[i].kernel_string;
410  kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string);
411  kernel_code_idx = i;
412  break;
413  }
414  }
415  if (!kernel_source) {
416  av_log(&opencl_ctx, AV_LOG_ERROR,
417  "Unable to find OpenCL kernel source '%s'\n", program_name);
418  goto end;
419  }
420 
421  /* create a CL program from kernel source */
422  program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status);
423  if(status != CL_SUCCESS) {
424  av_log(&opencl_ctx, AV_LOG_ERROR,
425  "Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status));
426  program = NULL;
427  goto end;
428  }
429  status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL);
430  if (status != CL_SUCCESS) {
431  av_log(&opencl_ctx, AV_LOG_ERROR,
432  "Compilation failed with OpenCL program: %s\n", program_name);
433  program = NULL;
434  goto end;
435  }
436 
437  opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1;
438 end:
440  return program;
441 }
442 
443 cl_command_queue av_opencl_get_command_queue(void)
444 {
445  return opencl_ctx.command_queue;
446 }
447 
448 #if FF_API_OLD_OPENCL
449 int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name)
450 {
451  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel %s, please update libavfilter.\n", kernel_name);
452  return AVERROR(EINVAL);
453 }
454 
455 void av_opencl_release_kernel(AVOpenCLKernelEnv *env)
456 {
457  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release OpenCL kernel, please update libavfilter.\n");
458 }
459 #endif
460 
461 static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
462 {
463  cl_int status;
464  cl_context_properties cps[3];
465  int i, ret = 0;
466  AVOpenCLDeviceNode *device_node = NULL;
467 
468  if (ext_opencl_env) {
469  if (opencl_ctx->is_user_created)
470  return 0;
471  opencl_ctx->platform_id = ext_opencl_env->platform_id;
472  opencl_ctx->is_user_created = 1;
473  opencl_ctx->command_queue = ext_opencl_env->command_queue;
474  opencl_ctx->context = ext_opencl_env->context;
475  opencl_ctx->device_id = ext_opencl_env->device_id;
476  opencl_ctx->device_type = ext_opencl_env->device_type;
477  } else {
478  if (!opencl_ctx->is_user_created) {
479  if (!opencl_ctx->device_list.platform_num) {
480  ret = get_device_list(&opencl_ctx->device_list);
481  if (ret < 0) {
482  return ret;
483  }
484  }
485  if (opencl_ctx->platform_idx >= 0) {
486  if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) {
487  av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n");
488  return AVERROR(EINVAL);
489  }
490  if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) {
491  av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n",
492  opencl_ctx->platform_idx);
493  return AVERROR(EINVAL);
494  }
495  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id;
496  } else {
497  /* get a usable platform by default*/
498  for (i = 0; i < opencl_ctx->device_list.platform_num; i++) {
499  if (opencl_ctx->device_list.platform_node[i]->device_num) {
500  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id;
501  opencl_ctx->platform_idx = i;
502  break;
503  }
504  }
505  }
506  if (!opencl_ctx->platform_id) {
507  av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n");
508  return AVERROR_EXTERNAL;
509  }
510  /* get a usable device*/
511  if (opencl_ctx->device_idx >= 0) {
512  if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) {
513  av_log(opencl_ctx, AV_LOG_ERROR,
514  "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx);
515  return AVERROR(EINVAL);
516  }
517  } else {
518  opencl_ctx->device_idx = 0;
519  }
520 
521  device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx];
522  opencl_ctx->device_id = device_node->device_id;
523  opencl_ctx->device_type = device_node->device_type;
524 
525  /*
526  * Use available platform.
527  */
528  av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, Device Name: %s\n",
529  opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
530  device_node->device_name);
531  cps[0] = CL_CONTEXT_PLATFORM;
532  cps[1] = (cl_context_properties)opencl_ctx->platform_id;
533  cps[2] = 0;
534 
535  opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type,
536  NULL, NULL, &status);
537  if (status != CL_SUCCESS) {
538  av_log(opencl_ctx, AV_LOG_ERROR,
539  "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status));
540  return AVERROR_EXTERNAL;
541  }
542  opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id,
543  0, &status);
544  if (status != CL_SUCCESS) {
545  av_log(opencl_ctx, AV_LOG_ERROR,
546  "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status));
547  return AVERROR_EXTERNAL;
548  }
549  }
550  }
551  return ret;
552 }
553 
555 {
556  int ret = 0;
557  LOCK_OPENCL;
558  if (!opencl_ctx.init_count) {
559  if (!opencl_ctx.opt_init_flag) {
560  av_opt_set_defaults(&opencl_ctx);
561  opencl_ctx.opt_init_flag = 1;
562  }
563  ret = init_opencl_env(&opencl_ctx, ext_opencl_env);
564  if (ret < 0)
565  goto end;
566  if (opencl_ctx.kernel_code_count <= 0) {
567  av_log(&opencl_ctx, AV_LOG_ERROR,
568  "No kernel code is registered, compile kernel file failed\n");
569  ret = AVERROR(EINVAL);
570  goto end;
571  }
572  }
573  opencl_ctx.init_count++;
574 end:
576  return ret;
577 }
578 
580 {
581  cl_int status;
582  LOCK_OPENCL;
583  opencl_ctx.init_count--;
584  if (opencl_ctx.is_user_created)
585  goto end;
586  if (opencl_ctx.init_count > 0)
587  goto end;
588  if (opencl_ctx.command_queue) {
589  status = clReleaseCommandQueue(opencl_ctx.command_queue);
590  if (status != CL_SUCCESS) {
591  av_log(&opencl_ctx, AV_LOG_ERROR,
592  "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status));
593  }
594  opencl_ctx.command_queue = NULL;
595  }
596  if (opencl_ctx.context) {
597  status = clReleaseContext(opencl_ctx.context);
598  if (status != CL_SUCCESS) {
599  av_log(&opencl_ctx, AV_LOG_ERROR,
600  "Could not release OpenCL context: %s\n", av_opencl_errstr(status));
601  }
602  opencl_ctx.context = NULL;
603  }
604  free_device_list(&opencl_ctx.device_list);
605 end:
606  if (opencl_ctx.init_count <= 0)
607  av_opt_free(&opencl_ctx); //FIXME: free openclutils context
609 }
610 
611 int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
612 {
613  cl_int status;
614  *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status);
615  if (status != CL_SUCCESS) {
616  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status));
617  return AVERROR_EXTERNAL;
618  }
619  return 0;
620 }
621 
622 void av_opencl_buffer_release(cl_mem *cl_buf)
623 {
624  cl_int status = 0;
625  if (!cl_buf)
626  return;
627  status = clReleaseMemObject(*cl_buf);
628  if (status != CL_SUCCESS) {
629  av_log(&opencl_ctx, AV_LOG_ERROR,
630  "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status));
631  }
632  memset(cl_buf, 0, sizeof(*cl_buf));
633 }
634 
635 int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
636 {
637  cl_int status;
638  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
639  CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size,
640  0, NULL, NULL, &status);
641 
642  if (status != CL_SUCCESS) {
643  av_log(&opencl_ctx, AV_LOG_ERROR,
644  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
645  return AVERROR_EXTERNAL;
646  }
647  memcpy(mapped, src_buf, buf_size);
648 
649  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
650  if (status != CL_SUCCESS) {
651  av_log(&opencl_ctx, AV_LOG_ERROR,
652  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
653  return AVERROR_EXTERNAL;
654  }
655  return 0;
656 }
657 
658 int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
659 {
660  cl_int status;
661  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
662  CL_TRUE, CL_MAP_READ, 0, buf_size,
663  0, NULL, NULL, &status);
664 
665  if (status != CL_SUCCESS) {
666  av_log(&opencl_ctx, AV_LOG_ERROR,
667  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
668  return AVERROR_EXTERNAL;
669  }
670  memcpy(dst_buf, mapped, buf_size);
671 
672  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
673  if (status != CL_SUCCESS) {
674  av_log(&opencl_ctx, AV_LOG_ERROR,
675  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
676  return AVERROR_EXTERNAL;
677  }
678  return 0;
679 }
680 
681 int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
682  uint8_t **src_data, int *plane_size, int plane_num)
683 {
684  int i, buffer_size = 0;
685  uint8_t *temp;
686  cl_int status;
687  void *mapped;
688  if ((unsigned int)plane_num > 8) {
689  return AVERROR(EINVAL);
690  }
691  for (i = 0;i < plane_num;i++) {
692  buffer_size += plane_size[i];
693  }
694  if (buffer_size > cl_buffer_size) {
695  av_log(&opencl_ctx, AV_LOG_ERROR,
696  "Cannot write image to OpenCL buffer: buffer too small\n");
697  return AVERROR(EINVAL);
698  }
699  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
700  CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
701  0, NULL, NULL, &status);
702  if (status != CL_SUCCESS) {
703  av_log(&opencl_ctx, AV_LOG_ERROR,
704  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
705  return AVERROR_EXTERNAL;
706  }
707  temp = mapped;
708  temp += dst_cl_offset;
709  for (i = 0; i < plane_num; i++) {
710  memcpy(temp, src_data[i], plane_size[i]);
711  temp += plane_size[i];
712  }
713  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
714  if (status != CL_SUCCESS) {
715  av_log(&opencl_ctx, AV_LOG_ERROR,
716  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
717  return AVERROR_EXTERNAL;
718  }
719  return 0;
720 }
721 
722 int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
723  cl_mem src_cl_buf, size_t cl_buffer_size)
724 {
725  int i,buffer_size = 0,ret = 0;
726  uint8_t *temp;
727  void *mapped;
728  cl_int status;
729  if ((unsigned int)plane_num > 8) {
730  return AVERROR(EINVAL);
731  }
732  for (i = 0; i < plane_num; i++) {
733  buffer_size += plane_size[i];
734  }
735  if (buffer_size > cl_buffer_size) {
736  av_log(&opencl_ctx, AV_LOG_ERROR,
737  "Cannot write image to CPU buffer: OpenCL buffer too small\n");
738  return AVERROR(EINVAL);
739  }
740  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
741  CL_TRUE, CL_MAP_READ, 0, buffer_size,
742  0, NULL, NULL, &status);
743 
744  if (status != CL_SUCCESS) {
745  av_log(&opencl_ctx, AV_LOG_ERROR,
746  "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
747  return AVERROR_EXTERNAL;
748  }
749  temp = mapped;
750  if (ret >= 0) {
751  for (i = 0; i < plane_num; i++) {
752  memcpy(dst_data[i], temp, plane_size[i]);
753  temp += plane_size[i];
754  }
755  }
756  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
757  if (status != CL_SUCCESS) {
758  av_log(&opencl_ctx, AV_LOG_ERROR,
759  "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
760  return AVERROR_EXTERNAL;
761  }
762  return 0;
763 }
764 
765 int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform,
766  int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env))
767 {
768  int64_t ret = 0;
769  cl_int status;
770  cl_context_properties cps[3];
771  AVOpenCLExternalEnv *ext_opencl_env = NULL;
772 
773  ext_opencl_env = av_opencl_alloc_external_env();
774  ext_opencl_env->device_id = device_node->device_id;
775  ext_opencl_env->device_type = device_node->device_type;
776  av_log(&opencl_ctx, AV_LOG_VERBOSE, "Performing test on OpenCL device %s\n",
777  device_node->device_name);
778 
779  cps[0] = CL_CONTEXT_PLATFORM;
780  cps[1] = (cl_context_properties)platform;
781  cps[2] = 0;
782  ext_opencl_env->context = clCreateContextFromType(cps, ext_opencl_env->device_type,
783  NULL, NULL, &status);
784  if (status != CL_SUCCESS || !ext_opencl_env->context) {
785  ret = AVERROR_EXTERNAL;
786  goto end;
787  }
788  ext_opencl_env->command_queue = clCreateCommandQueue(ext_opencl_env->context,
789  ext_opencl_env->device_id, 0, &status);
790  if (status != CL_SUCCESS || !ext_opencl_env->command_queue) {
791  ret = AVERROR_EXTERNAL;
792  goto end;
793  }
794  ret = benchmark(ext_opencl_env);
795  if (ret < 0)
796  av_log(&opencl_ctx, AV_LOG_ERROR, "Benchmark failed with OpenCL device %s\n",
797  device_node->device_name);
798 end:
799  if (ext_opencl_env->command_queue)
800  clReleaseCommandQueue(ext_opencl_env->command_queue);
801  if (ext_opencl_env->context)
802  clReleaseContext(ext_opencl_env->context);
803  av_opencl_free_external_env(&ext_opencl_env);
804  return ret;
805 }