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