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 };
85 
86 static const AVClass openclutils_class = {
87  .class_name = "OPENCLUTILS",
88  .option = opencl_options,
89  .item_name = av_default_item_name,
90  .version = LIBAVUTIL_VERSION_INT,
91  .log_level_offset_offset = offsetof(OpenclContext, log_offset),
92  .parent_log_context_offset = offsetof(OpenclContext, log_ctx),
93 };
94 
95 static OpenclContext opencl_ctx = {&openclutils_class};
96 
97 static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT};
98 
99 typedef struct {
100  int err_code;
101  const char *err_str;
103 
104 static const OpenclErrorMsg opencl_err_msg[] = {
105  {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"},
106  {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"},
107  {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"},
108  {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"},
109  {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"},
110  {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"},
111  {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"},
112  {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"},
113  {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"},
114  {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"},
115  {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"},
116  {CL_MAP_FAILURE, "MAP FAILURE"},
117  {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"},
118  {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
119  {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"},
120  {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"},
121  {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"},
122  {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"},
123  {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"},
124  {CL_INVALID_VALUE, "INVALID VALUE"},
125  {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"},
126  {CL_INVALID_PLATFORM, "INVALID PLATFORM"},
127  {CL_INVALID_DEVICE, "INVALID DEVICE"},
128  {CL_INVALID_CONTEXT, "INVALID CONTEXT"},
129  {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"},
130  {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"},
131  {CL_INVALID_HOST_PTR, "INVALID HOST PTR"},
132  {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"},
133  {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"},
134  {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"},
135  {CL_INVALID_SAMPLER, "INVALID SAMPLER"},
136  {CL_INVALID_BINARY, "INVALID BINARY"},
137  {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"},
138  {CL_INVALID_PROGRAM, "INVALID PROGRAM"},
139  {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"},
140  {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"},
141  {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"},
142  {CL_INVALID_KERNEL, "INVALID KERNEL"},
143  {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"},
144  {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"},
145  {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"},
146  {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"},
147  {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"},
148  {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"},
149  {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"},
150  {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"},
151  {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"},
152  {CL_INVALID_EVENT, "INVALID EVENT"},
153  {CL_INVALID_OPERATION, "INVALID OPERATION"},
154  {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"},
155  {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"},
156  {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"},
157  {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"},
158  {CL_INVALID_PROPERTY, "INVALID PROPERTY"},
159  {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"},
160  {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"},
161  {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"},
162  {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"},
163 };
164 
165 static const char *opencl_errstr(cl_int status)
166 {
167  int i;
168  for (i = 0; i < sizeof(opencl_err_msg); i++) {
169  if (opencl_err_msg[i].err_code == status)
170  return opencl_err_msg[i].err_str;
171  }
172  return "unknown error";
173 }
174 
175 static void free_device_list(AVOpenCLDeviceList *device_list)
176 {
177  int i, j;
178  if (!device_list)
179  return;
180  for (i = 0; i < device_list->platform_num; i++) {
181  if (!device_list->platform_node[i])
182  continue;
183  for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
184  av_freep(&(device_list->platform_node[i]->device_node[j]));
185  }
186  av_freep(&device_list->platform_node[i]->device_node);
187  av_freep(&device_list->platform_node[i]);
188  }
189  av_freep(&device_list->platform_node);
190  device_list->platform_num = 0;
191 }
192 
193 static int get_device_list(AVOpenCLDeviceList *device_list)
194 {
195  cl_int status;
196  int i, j, k, device_num, total_devices_num,ret = 0;
197  int *devices_num;
198  cl_platform_id *platform_ids = NULL;
199  cl_device_id *device_ids = NULL;
200  AVOpenCLDeviceNode *device_node = NULL;
201  status = clGetPlatformIDs(0, NULL, &device_list->platform_num);
202  if (status != CL_SUCCESS) {
203  av_log(&opencl_ctx, AV_LOG_ERROR,
204  "Could not get OpenCL platform ids: %s\n", opencl_errstr(status));
205  return AVERROR_EXTERNAL;
206  }
207  platform_ids = av_mallocz(device_list->platform_num * sizeof(cl_platform_id));
208  if (!platform_ids)
209  return AVERROR(ENOMEM);
210  status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL);
211  if (status != CL_SUCCESS) {
212  av_log(&opencl_ctx, AV_LOG_ERROR,
213  "Could not get OpenCL platform ids: %s\n", opencl_errstr(status));
214  ret = AVERROR_EXTERNAL;
215  goto end;
216  }
217  device_list->platform_node = av_mallocz(device_list->platform_num * sizeof(AVOpenCLPlatformNode *));
218  if (!device_list->platform_node) {
219  ret = AVERROR(ENOMEM);
220  goto end;
221  }
222  devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type));
223  if (!devices_num) {
224  ret = AVERROR(ENOMEM);
225  goto end;
226  }
227  for (i = 0; i < device_list->platform_num; i++) {
228  device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode));
229  if (!device_list->platform_node[i]) {
230  ret = AVERROR(ENOMEM);
231  goto end;
232  }
233  device_list->platform_node[i]->platform_id = platform_ids[i];
234  status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
235  sizeof(device_list->platform_node[i]->platform_name),
236  device_list->platform_node[i]->platform_name, NULL);
237  total_devices_num = 0;
238  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
239  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id,
240  device_type[j], 0, NULL, &devices_num[j]);
241  total_devices_num += devices_num[j];
242  }
243  device_list->platform_node[i]->device_node = av_mallocz(total_devices_num * sizeof(AVOpenCLDeviceNode *));
244  if (!device_list->platform_node[i]->device_node) {
245  ret = AVERROR(ENOMEM);
246  goto end;
247  }
248  for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
249  if (devices_num[j]) {
250  device_ids = av_mallocz(devices_num[j] * sizeof(cl_device_id));
251  if (!device_ids) {
252  ret = AVERROR(ENOMEM);
253  goto end;
254  }
255  status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j],
256  devices_num[j], device_ids, NULL);
257  if (status != CL_SUCCESS) {
258  av_log(&opencl_ctx, AV_LOG_WARNING,
259  "Could not get device ID: %s:\n", opencl_errstr(status));
260  av_freep(&device_ids);
261  continue;
262  }
263  for (k = 0; k < devices_num[j]; k++) {
264  device_num = device_list->platform_node[i]->device_num;
265  device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode));
266  if (!device_list->platform_node[i]->device_node[device_num]) {
267  ret = AVERROR(ENOMEM);
268  goto end;
269  }
270  device_node = device_list->platform_node[i]->device_node[device_num];
271  device_node->device_id = device_ids[k];
272  device_node->device_type = device_type[j];
273  status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
274  sizeof(device_node->device_name), device_node->device_name,
275  NULL);
276  if (status != CL_SUCCESS) {
277  av_log(&opencl_ctx, AV_LOG_WARNING,
278  "Could not get device name: %s\n", opencl_errstr(status));
279  continue;
280  }
281  device_list->platform_node[i]->device_num++;
282  }
283  av_freep(&device_ids);
284  }
285  }
286  }
287 end:
288  av_freep(&platform_ids);
289  av_freep(&devices_num);
290  av_freep(&device_ids);
291  if (ret < 0)
292  free_device_list(device_list);
293  return ret;
294 }
295 
297 {
298  int ret = 0;
299  *device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
300  if (!(*device_list)) {
301  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n");
302  return AVERROR(ENOMEM);
303  }
304  ret = get_device_list(*device_list);
305  if (ret < 0) {
306  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n");
307  free_device_list(*device_list);
308  av_freep(device_list);
309  return ret;
310  }
311  return ret;
312 }
313 
315 {
316  free_device_list(*device_list);
317  av_freep(device_list);
318 }
319 
320 int av_opencl_set_option(const char *key, const char *val)
321 {
322  int ret = 0;
324  if (!opencl_ctx.opt_init_flag) {
325  av_opt_set_defaults(&opencl_ctx);
326  opencl_ctx.opt_init_flag = 1;
327  }
328  ret = av_opt_set(&opencl_ctx, key, val, 0);
330  return ret;
331 }
332 
333 int av_opencl_get_option(const char *key, uint8_t **out_val)
334 {
335  int ret = 0;
337  ret = av_opt_get(&opencl_ctx, key, 0, out_val);
339  return ret;
340 }
341 
343 {
344  /*FIXME: free openclutils context*/
346  av_opt_free(&opencl_ctx);
348 }
349 
351 {
353  if (!ext) {
354  av_log(&opencl_ctx, AV_LOG_ERROR,
355  "Could not malloc external opencl environment data space\n");
356  }
357  return ext;
358 }
359 
361 {
362  av_freep(ext_opencl_env);
363 }
364 
365 int av_opencl_register_kernel_code(const char *kernel_code)
366 {
367  int i, ret = 0;
368  LOCK_OPENCL;
369  if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) {
370  av_log(&opencl_ctx, AV_LOG_ERROR,
371  "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
373  ret = AVERROR(EINVAL);
374  goto end;
375  }
376  for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
377  if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) {
378  av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n");
379  goto end;
380  }
381  }
382  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code;
383  opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0;
384  opencl_ctx.kernel_code_count++;
385 end:
387  return ret;
388 }
389 
390 int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name)
391 {
392  cl_int status;
393  int i, ret = 0;
394  LOCK_OPENCL;
395  if (strlen(kernel_name) + 1 > AV_OPENCL_MAX_KERNEL_NAME_SIZE) {
396  av_log(&opencl_ctx, AV_LOG_ERROR, "Created kernel name %s is too long\n", kernel_name);
397  ret = AVERROR(EINVAL);
398  goto end;
399  }
400  if (!env->kernel) {
401  if (opencl_ctx.kernel_count >= MAX_KERNEL_NUM) {
402  av_log(&opencl_ctx, AV_LOG_ERROR,
403  "Could not create kernel with name '%s', maximum number of kernels %d already reached\n",
404  kernel_name, MAX_KERNEL_NUM);
405  ret = AVERROR(EINVAL);
406  goto end;
407  }
408  if (opencl_ctx.program_count == 0) {
409  av_log(&opencl_ctx, AV_LOG_ERROR, "Program count of OpenCL is 0, can not create kernel\n");
410  ret = AVERROR(EINVAL);
411  goto end;
412  }
413  for (i = 0; i < opencl_ctx.program_count; i++) {
414  env->kernel = clCreateKernel(opencl_ctx.programs[i], kernel_name, &status);
415  if (status == CL_SUCCESS)
416  break;
417  }
418  if (status != CL_SUCCESS) {
419  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel: %s\n", opencl_errstr(status));
420  ret = AVERROR_EXTERNAL;
421  goto end;
422  }
423  opencl_ctx.kernel_count++;
424  env->command_queue = opencl_ctx.command_queue;
425  av_strlcpy(env->kernel_name, kernel_name, sizeof(env->kernel_name));
426  }
427 end:
429  return ret;
430 }
431 
433 {
434  cl_int status;
436  if (!env->kernel)
437  goto end;
438  status = clReleaseKernel(env->kernel);
439  if (status != CL_SUCCESS) {
440  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release kernel: %s\n",
441  opencl_errstr(status));
442  }
443  env->kernel = NULL;
444  env->command_queue = NULL;
445  env->kernel_name[0] = 0;
446  opencl_ctx.kernel_count--;
447 end:
449 }
450 
451 static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
452 {
453  cl_int status;
454  cl_context_properties cps[3];
455  int i, ret = 0;
456  AVOpenCLDeviceNode *device_node = NULL;
457 
458  if (ext_opencl_env) {
459  if (opencl_ctx->is_user_created)
460  return 0;
461  opencl_ctx->platform_id = ext_opencl_env->platform_id;
462  opencl_ctx->is_user_created = 1;
463  opencl_ctx->command_queue = ext_opencl_env->command_queue;
464  opencl_ctx->context = ext_opencl_env->context;
465  opencl_ctx->device_id = ext_opencl_env->device_id;
466  opencl_ctx->device_type = ext_opencl_env->device_type;
467  } else {
468  if (!opencl_ctx->is_user_created) {
469  if (!opencl_ctx->device_list.platform_num) {
470  ret = get_device_list(&opencl_ctx->device_list);
471  if (ret < 0) {
472  return ret;
473  }
474  }
475  if (opencl_ctx->platform_idx >= 0) {
476  if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) {
477  av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n");
478  return AVERROR(EINVAL);
479  }
480  if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) {
481  av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n",
482  opencl_ctx->platform_idx);
483  return AVERROR(EINVAL);
484  }
485  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id;
486  } else {
487  /* get a usable platform by default*/
488  for (i = 0; i < opencl_ctx->device_list.platform_num; i++) {
489  if (opencl_ctx->device_list.platform_node[i]->device_num) {
490  opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id;
491  opencl_ctx->platform_idx = i;
492  break;
493  }
494  }
495  }
496  if (!opencl_ctx->platform_id) {
497  av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n");
498  return AVERROR_EXTERNAL;
499  }
500  /* get a usable device*/
501  if (opencl_ctx->device_idx >= 0) {
502  if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) {
503  av_log(opencl_ctx, AV_LOG_ERROR,
504  "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx);
505  return AVERROR(EINVAL);
506  }
507  } else {
508  opencl_ctx->device_idx = 0;
509  }
510 
511  device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx];
512  opencl_ctx->device_id = device_node->device_id;
513  opencl_ctx->device_type = device_node->device_type;
514 
515  /*
516  * Use available platform.
517  */
518  av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, device id: 0x%x\n",
519  opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
520  (unsigned int)opencl_ctx->device_id);
521  cps[0] = CL_CONTEXT_PLATFORM;
522  cps[1] = (cl_context_properties)opencl_ctx->platform_id;
523  cps[2] = 0;
524 
525  opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type,
526  NULL, NULL, &status);
527  if (status != CL_SUCCESS) {
528  av_log(opencl_ctx, AV_LOG_ERROR,
529  "Could not get OpenCL context from device type: %s\n", opencl_errstr(status));
530  return AVERROR_EXTERNAL;
531  }
532  opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id,
533  0, &status);
534  if (status != CL_SUCCESS) {
535  av_log(opencl_ctx, AV_LOG_ERROR,
536  "Could not create OpenCL command queue: %s\n", opencl_errstr(status));
537  return AVERROR_EXTERNAL;
538  }
539  }
540  }
541  return ret;
542 }
543 
544 static int compile_kernel_file(OpenclContext *opencl_ctx)
545 {
546  cl_int status;
547  char *temp, *source_str = NULL;
548  size_t source_str_len = 0;
549  int i, ret = 0;
550 
551  for (i = 0; i < opencl_ctx->kernel_code_count; i++) {
552  if (!opencl_ctx->kernel_code[i].is_compiled)
553  source_str_len += strlen(opencl_ctx->kernel_code[i].kernel_string);
554  }
555  if (!source_str_len) {
556  return 0;
557  }
558  source_str = av_mallocz(source_str_len + 1);
559  if (!source_str) {
560  return AVERROR(ENOMEM);
561  }
562  temp = source_str;
563  for (i = 0; i < opencl_ctx->kernel_code_count; i++) {
564  if (!opencl_ctx->kernel_code[i].is_compiled) {
565  memcpy(temp, opencl_ctx->kernel_code[i].kernel_string,
566  strlen(opencl_ctx->kernel_code[i].kernel_string));
567  opencl_ctx->kernel_code[i].is_compiled = 1;
568  temp += strlen(opencl_ctx->kernel_code[i].kernel_string);
569  }
570  }
571  /* create a CL program using the kernel source */
572  opencl_ctx->programs[opencl_ctx->program_count] = clCreateProgramWithSource(opencl_ctx->context,
573  1, (const char **)(&source_str),
574  &source_str_len, &status);
575  if(status != CL_SUCCESS) {
576  av_log(opencl_ctx, AV_LOG_ERROR,
577  "Could not create OpenCL program with source code: %s\n", opencl_errstr(status));
578  ret = AVERROR_EXTERNAL;
579  goto end;
580  }
581  if (!opencl_ctx->programs[opencl_ctx->program_count]) {
582  av_log(opencl_ctx, AV_LOG_ERROR, "Created program is NULL\n");
583  ret = AVERROR_EXTERNAL;
584  goto end;
585  }
586  status = clBuildProgram(opencl_ctx->programs[opencl_ctx->program_count], 1, &(opencl_ctx->device_id),
587  opencl_ctx->build_options, NULL, NULL);
588  if (status != CL_SUCCESS) {
589  av_log(opencl_ctx, AV_LOG_ERROR,
590  "Could not compile OpenCL kernel: %s\n", opencl_errstr(status));
591  ret = AVERROR_EXTERNAL;
592  goto end;
593  }
594  opencl_ctx->program_count++;
595 end:
596  av_free(source_str);
597  return ret;
598 }
599 
601 {
602  int ret = 0;
604  if (!opencl_ctx.init_count) {
605  if (!opencl_ctx.opt_init_flag) {
606  av_opt_set_defaults(&opencl_ctx);
607  opencl_ctx.opt_init_flag = 1;
608  }
609  ret = init_opencl_env(&opencl_ctx, ext_opencl_env);
610  if (ret < 0)
611  goto end;
612  }
613  ret = compile_kernel_file(&opencl_ctx);
614  if (ret < 0)
615  goto end;
616  if (opencl_ctx.kernel_code_count <= 0) {
617  av_log(&opencl_ctx, AV_LOG_ERROR,
618  "No kernel code is registered, compile kernel file failed\n");
619  ret = AVERROR(EINVAL);
620  goto end;
621  }
622  opencl_ctx.init_count++;
623 
624 end:
626  return ret;
627 }
628 
630 {
631  cl_int status;
632  int i;
634  opencl_ctx.init_count--;
635  if (opencl_ctx.is_user_created)
636  goto end;
637  if (opencl_ctx.init_count > 0 || opencl_ctx.kernel_count > 0)
638  goto end;
639  for (i = 0; i < opencl_ctx.program_count; i++) {
640  if (opencl_ctx.programs[i]) {
641  status = clReleaseProgram(opencl_ctx.programs[i]);
642  if (status != CL_SUCCESS) {
643  av_log(&opencl_ctx, AV_LOG_ERROR,
644  "Could not release OpenCL program: %s\n", opencl_errstr(status));
645  }
646  opencl_ctx.programs[i] = NULL;
647  }
648  }
649  if (opencl_ctx.command_queue) {
650  status = clReleaseCommandQueue(opencl_ctx.command_queue);
651  if (status != CL_SUCCESS) {
652  av_log(&opencl_ctx, AV_LOG_ERROR,
653  "Could not release OpenCL command queue: %s\n", opencl_errstr(status));
654  }
655  opencl_ctx.command_queue = NULL;
656  }
657  if (opencl_ctx.context) {
658  status = clReleaseContext(opencl_ctx.context);
659  if (status != CL_SUCCESS) {
660  av_log(&opencl_ctx, AV_LOG_ERROR,
661  "Could not release OpenCL context: %s\n", opencl_errstr(status));
662  }
663  opencl_ctx.context = NULL;
664  }
665  free_device_list(&opencl_ctx.device_list);
666 end:
667  if ((opencl_ctx.init_count <= 0) && (opencl_ctx.kernel_count <= 0))
668  av_opt_free(&opencl_ctx); //FIXME: free openclutils context
670 }
671 
672 int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
673 {
674  cl_int status;
675  *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status);
676  if (status != CL_SUCCESS) {
677  av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", opencl_errstr(status));
678  return AVERROR_EXTERNAL;
679  }
680  return 0;
681 }
682 
683 void av_opencl_buffer_release(cl_mem *cl_buf)
684 {
685  cl_int status = 0;
686  if (!cl_buf)
687  return;
688  status = clReleaseMemObject(*cl_buf);
689  if (status != CL_SUCCESS) {
690  av_log(&opencl_ctx, AV_LOG_ERROR,
691  "Could not release OpenCL buffer: %s\n", opencl_errstr(status));
692  }
693  memset(cl_buf, 0, sizeof(*cl_buf));
694 }
695 
696 int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
697 {
698  cl_int status;
699  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
700  CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size,
701  0, NULL, NULL, &status);
702 
703  if (status != CL_SUCCESS) {
704  av_log(&opencl_ctx, AV_LOG_ERROR,
705  "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
706  return AVERROR_EXTERNAL;
707  }
708  memcpy(mapped, src_buf, buf_size);
709 
710  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
711  if (status != CL_SUCCESS) {
712  av_log(&opencl_ctx, AV_LOG_ERROR,
713  "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
714  return AVERROR_EXTERNAL;
715  }
716  return 0;
717 }
718 
719 int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
720 {
721  cl_int status;
722  void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
723  CL_TRUE, CL_MAP_READ, 0, buf_size,
724  0, NULL, NULL, &status);
725 
726  if (status != CL_SUCCESS) {
727  av_log(&opencl_ctx, AV_LOG_ERROR,
728  "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
729  return AVERROR_EXTERNAL;
730  }
731  memcpy(dst_buf, mapped, buf_size);
732 
733  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
734  if (status != CL_SUCCESS) {
735  av_log(&opencl_ctx, AV_LOG_ERROR,
736  "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
737  return AVERROR_EXTERNAL;
738  }
739  return 0;
740 }
741 
742 int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
743  uint8_t **src_data, int *plane_size, int plane_num)
744 {
745  int i, buffer_size = 0;
746  uint8_t *temp;
747  cl_int status;
748  void *mapped;
749  if ((unsigned int)plane_num > 8) {
750  return AVERROR(EINVAL);
751  }
752  for (i = 0;i < plane_num;i++) {
753  buffer_size += plane_size[i];
754  }
755  if (buffer_size > cl_buffer_size) {
756  av_log(&opencl_ctx, AV_LOG_ERROR,
757  "Cannot write image to OpenCL buffer: buffer too small\n");
758  return AVERROR(EINVAL);
759  }
760  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
761  CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
762  0, NULL, NULL, &status);
763  if (status != CL_SUCCESS) {
764  av_log(&opencl_ctx, AV_LOG_ERROR,
765  "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
766  return AVERROR_EXTERNAL;
767  }
768  temp = mapped;
769  temp += dst_cl_offset;
770  for (i = 0; i < plane_num; i++) {
771  memcpy(temp, src_data[i], plane_size[i]);
772  temp += plane_size[i];
773  }
774  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
775  if (status != CL_SUCCESS) {
776  av_log(&opencl_ctx, AV_LOG_ERROR,
777  "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
778  return AVERROR_EXTERNAL;
779  }
780  return 0;
781 }
782 
783 int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
784  cl_mem src_cl_buf, size_t cl_buffer_size)
785 {
786  int i,buffer_size = 0,ret = 0;
787  uint8_t *temp;
788  void *mapped;
789  cl_int status;
790  if ((unsigned int)plane_num > 8) {
791  return AVERROR(EINVAL);
792  }
793  for (i = 0; i < plane_num; i++) {
794  buffer_size += plane_size[i];
795  }
796  if (buffer_size > cl_buffer_size) {
797  av_log(&opencl_ctx, AV_LOG_ERROR,
798  "Cannot write image to CPU buffer: OpenCL buffer too small\n");
799  return AVERROR(EINVAL);
800  }
801  mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
802  CL_TRUE, CL_MAP_READ, 0, buffer_size,
803  0, NULL, NULL, &status);
804 
805  if (status != CL_SUCCESS) {
806  av_log(&opencl_ctx, AV_LOG_ERROR,
807  "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
808  return AVERROR_EXTERNAL;
809  }
810  temp = mapped;
811  if (ret >= 0) {
812  for (i = 0; i < plane_num; i++) {
813  memcpy(dst_data[i], temp, plane_size[i]);
814  temp += plane_size[i];
815  }
816  }
817  status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
818  if (status != CL_SUCCESS) {
819  av_log(&opencl_ctx, AV_LOG_ERROR,
820  "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
821  return AVERROR_EXTERNAL;
822  }
823  return 0;
824 }
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
static int compile_kernel_file(OpenclContext *opencl_ctx)
Definition: opencl.c:544
char platform_name[AV_OPENCL_MAX_PLATFORM_NAME_SIZE]
Definition: opencl.h:54
int init_count
Definition: opencl.c:55
cl_kernel kernel
Definition: opencl.h:66
AVOption.
Definition: opt.h:251
char kernel_name[AV_OPENCL_MAX_KERNEL_NAME_SIZE]
Definition: opencl.h:67
av_default_item_name
else temp
Definition: vf_mcdeint.c:148
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
Definition: opt.c:942
KernelCode kernel_code[MAX_KERNEL_CODE_NUM]
Definition: opencl.c:73
void * log_ctx
Definition: opencl.c:54
#define FF_ARRAY_ELEMS(a)
#define LOCK_OPENCL
Definition: opencl.c:38
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:719
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
Definition: opencl.c:451
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:55
HMTX pthread_mutex_t
Definition: os2threads.h:38
uint8_t
AVOptions.
end end
static const cl_device_type device_type[]
Definition: opencl.c:97
cl_platform_id platform_id
Definition: opencl.h:53
int av_opencl_get_device_list(AVOpenCLDeviceList **device_list)
Get OpenCL device list.
Definition: opencl.c:296
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
#define MAX_KERNEL_CODE_NUM
Definition: opencl.c:44
static const OpenclErrorMsg opencl_err_msg[]
Definition: opencl.c:104
int opt_init_flag
Definition: opencl.c:56
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
cl_platform_id platform_id
Definition: opencl.c:65
cl_device_id device_id
Definition: opencl.h:49
#define MAX_KERNEL_NUM
Definition: opencl.c:43
cl_device_id device_id
Definition: opencl.h:74
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:82
AVOpenCLDeviceList device_list
Definition: opencl.c:75
AVOpenCLDeviceNode ** device_node
Definition: opencl.h:56
#define AV_LOG_VERBOSE
Definition: log.h:157
cl_platform_id platform_id
Definition: opencl.h:71
static const AVOption opencl_options[]
Definition: opencl.c:80
int is_compiled
Definition: opencl.c:47
static void free_device_list(AVOpenCLDeviceList *device_list)
Definition: opencl.c:175
ret
Definition: avfilter.c:821
cl_program programs[MAX_KERNEL_CODE_NUM]
Definition: opencl.c:71
int kernel_count
Definition: opencl.c:74
int av_opencl_set_option(const char *key, const char *val)
Set option in the global OpenCL context.
Definition: opencl.c:320
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:672
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
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:742
int program_count
Definition: opencl.c:70
#define OFFSET(x)
Definition: opencl.c:78
static const AVClass openclutils_class
Definition: opencl.c:86
for k
NULL
Definition: eval.c:55
cl_device_type device_type
Definition: opencl.h:72
static OpenclContext opencl_ctx
Definition: opencl.c:95
AVOpenCLPlatformNode ** platform_node
Definition: opencl.h:61
void av_opencl_release_kernel(AVOpenCLKernelEnv *env)
Release kernel object.
Definition: opencl.c:432
int av_opencl_register_kernel_code(const char *kernel_code)
Register kernel code.
Definition: opencl.c:365
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env)
Free OpenCL external environment.
Definition: opencl.c:360
int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name)
Create kernel object in the specified kernel environment.
Definition: opencl.c:390
Describe the class of an AVClass context structure.
Definition: log.h:50
synthesis window for stochastic i
void av_opencl_free_option(void)
Free option values of the global OpenCL context.
Definition: opencl.c:342
AVOpenCLExternalEnv * av_opencl_alloc_external_env(void)
Allocate OpenCL external environment.
Definition: opencl.c:350
void av_opencl_buffer_release(cl_mem *cl_buf)
Release OpenCL buffer.
Definition: opencl.c:683
cl_context context
Definition: opencl.c:67
cl_command_queue command_queue
Definition: opencl.h:75
static int get_device_list(AVOpenCLDeviceList *device_list)
Definition: opencl.c:193
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:61
#define AV_OPENCL_MAX_KERNEL_NAME_SIZE
Definition: opencl.h:40
const char * kernel_string
Definition: opencl.c:48
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
char * build_options
Definition: opencl.c:64
int err_code
Definition: opencl.c:100
static int flags
Definition: cpu.c:23
char device_name[AV_OPENCL_MAX_DEVICE_NAME_SIZE]
Definition: opencl.h:48
void av_opt_free(void *obj)
Free all string and binary options in obj.
Definition: opt.c:1194
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:696
void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
Free OpenCL device list.
Definition: opencl.c:314
int platform_idx
Definition: opencl.c:62
void av_opencl_uninit(void)
Release OpenCL environment.
Definition: opencl.c:629
cl_device_id device_id
Definition: opencl.c:68
cl_context context
Definition: opencl.h:73
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:566
cl_command_queue command_queue
Definition: opencl.h:65
int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
Initialize the run time OpenCL environment and compile the kernel code registered with av_opencl_regi...
Definition: opencl.c:600
int log_offset
Definition: opencl.c:53
cl_device_type device_type
Definition: opencl.c:66
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:333
cl_command_queue command_queue
Definition: opencl.c:69
int kernel_code_count
Definition: opencl.c:72
const char * err_str
Definition: opencl.c:101
int device_idx
Definition: opencl.c:63
#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:252
static const char * opencl_errstr(cl_int status)
Definition: opencl.c:165
#define UNLOCK_OPENCL
Definition: opencl.c:39
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:783