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
29
30 #if HAVE_THREADS
31 #include "thread.h"
33
35 #define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock)
36 #define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock)
37 #else
40 #endif
41
42 #define MAX_KERNEL_CODE_NUM 200
43
48
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 */
71
72 #define OFFSET(x) offsetof(OpenclContext, x)
73
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},
78 };
79
85 .log_level_offset_offset = offsetof(
OpenclContext, log_offset),
86 .parent_log_context_offset = offsetof(
OpenclContext, log_ctx),
87 };
88
90
91 static const cl_device_type
device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU};
92
97
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
160 {
161 int 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
170 {
171 int i, j;
172 if (!device_list)
173 return;
176 continue;
180 }
184 }
187 }
188
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;
197 size_t platform_name_size = 0;
198 size_t device_name_size = 0;
200 if (status != CL_SUCCESS) {
204 }
206 if (!platform_ids)
209 if (status != CL_SUCCESS) {
214 }
219 }
221 if (!devices_num) {
224 }
230 }
232 status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
233 0,
NULL, &platform_name_size);
234 if (status != CL_SUCCESS) {
237 } else {
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),
246 if (status != CL_SUCCESS) {
249 }
250 }
251 }
252 total_devices_num = 0;
256 total_devices_num += devices_num[j];
257 }
262 }
264 if (devices_num[j]) {
266 if (!device_ids) {
269 }
271 devices_num[j], device_ids,
NULL);
272 if (status != CL_SUCCESS) {
276 continue;
277 }
278 for (k = 0; k < devices_num[j]; k++) {
284 }
288 status = clGetDeviceInfo(device_node->
device_id, CL_DEVICE_NAME,
289 0,
NULL, &device_name_size);
290 if (status != CL_SUCCESS) {
293 continue;
294 }
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),
304 if (status != CL_SUCCESS) {
307 continue;
308 }
310 }
312 }
313 }
314 }
319 if (ret < 0)
321 return ret;
322 }
323
325 {
326 int ret = 0;
328 if (!(*device_list)) {
331 }
333 if (ret < 0) {
337 return ret;
338 }
339 return ret;
340 }
341
343 {
346 }
347
349 {
350 #if HAVE_THREADS
351 if (!atomic_opencl_lock) {
352 int err;
354 if (!tmp)
359 }
363 }
364 }
365 #endif
366 return 0;
367 }
368
370 {
372 if (ret < 0)
373 return ret;
378 }
381 return ret;
382 }
383
385 {
386 int ret = 0;
388 ret =
av_opt_get(&opencl_ctx, key, 0, out_val);
390 return ret;
391 }
392
394 {
395 /*FIXME: free openclutils context*/
399 }
400
402 {
404 if (!ext) {
406 "Could not malloc external opencl environment data space\n");
407 }
408 return ext;
409 }
410
412 {
414 }
415
417 {
419 if (ret < 0)
420 return ret;
424 "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
428 }
433 }
434 }
440 return ret;
441 }
442
444 {
445 int i;
446 cl_int status, build_status;
447 int kernel_code_idx = 0;
448 const char *kernel_source;
449 size_t kernel_code_len;
451 cl_program program =
NULL;
452 size_t log_size;
454
457 // identify a program using a unique name within the kernel source
462 kernel_code_idx = i;
463 break;
464 }
465 }
466 if (!kernel_source) {
468 "Unable to find OpenCL kernel source '%s'\n", program_name);
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) {
476 "Unable to create OpenCL program '%s': %s\n", program_name,
av_opencl_errstr(status));
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) {
486 "Failed to get compilation log: %s\n",
488 } else {
490 if (log) {
491 status = clGetProgramBuildInfo(program, opencl_ctx.
device_id,
492 CL_PROGRAM_BUILD_LOG, log_size,
494 if (status != CL_SUCCESS) {
496 "Failed to get compilation log: %s\n",
498 } else {
501 av_log(&opencl_ctx, level,
"Compilation log:\n%s\n", log);
502 }
503 }
505 }
506 if (build_status != CL_SUCCESS) {
508 "Compilation failed with OpenCL program '%s': %s\n",
512 }
513
517 return program;
518 }
519
521 {
523 }
524
526 {
527 cl_int status;
528 cl_context_properties cps[3];
529 int i, ret = 0;
531
532 if (ext_opencl_env) {
534 return 0;
541 } else {
545 if (ret < 0) {
546 return ret;
547 }
548 }
553 }
555 av_log(opencl_ctx,
AV_LOG_ERROR,
"No devices in user specific platform with index %d\n",
558 }
560 } else {
561 /* get a usable platform by default*/
566 break;
567 }
568 }
569 }
573 }
574 /* get a usable device*/
578 "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->
platform_idx);
580 }
581 } else {
583 }
584
588
589 /*
590 * Use available platform.
591 */
595 cps[0] = CL_CONTEXT_PLATFORM;
596 cps[1] = (cl_context_properties)opencl_ctx->
platform_id;
597 cps[2] = 0;
598
601 if (status != CL_SUCCESS) {
603 "Could not get OpenCL context from device type: %s\n",
av_opencl_errstr(status));
605 }
607 0, &status);
608 if (status != CL_SUCCESS) {
612 }
613 }
614 }
615 return ret;
616 }
617
619 {
621 if (ret < 0)
622 return ret;
628 }
630 if (ret < 0)
634 "No kernel code is registered, compile kernel file failed\n");
637 }
638 }
642 return ret;
643 }
644
646 {
647 int i;
648 cl_int status;
657 if (status != CL_SUCCESS) {
660 }
662 }
664 status = clReleaseContext(opencl_ctx.
context);
665 if (status != CL_SUCCESS) {
668 }
670 }
673 }
677 av_opt_free(&opencl_ctx);
//FIXME: free openclutils context
679 }
680
682 {
683 cl_int status;
684 *cl_buf = clCreateBuffer(opencl_ctx.
context, flags, cl_buf_size, host_ptr, &status);
685 if (status != CL_SUCCESS) {
688 }
689 return 0;
690 }
691
693 {
694 cl_int status = 0;
695 if (!cl_buf)
696 return;
697 status = clReleaseMemObject(*cl_buf);
698 if (status != CL_SUCCESS) {
701 }
702 memset(cl_buf, 0, sizeof(*cl_buf));
703 }
704
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,
711
712 if (status != CL_SUCCESS) {
716 }
717 memcpy(mapped, src_buf, buf_size);
718
720 if (status != CL_SUCCESS) {
724 }
725 return 0;
726 }
727
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,
734
735 if (status != CL_SUCCESS) {
739 }
740 memcpy(dst_buf, mapped, buf_size);
741
743 if (status != CL_SUCCESS) {
747 }
748 return 0;
749 }
750
752 uint8_t **src_data,
int *plane_size,
int plane_num)
753 {
754 int i, buffer_size = 0;
756 cl_int status;
757 void *mapped;
758 if ((unsigned int)plane_num > 8) {
760 }
761 for (i = 0;i < plane_num;i++) {
762 buffer_size += plane_size[i];
763 }
764 if (buffer_size > cl_buffer_size) {
766 "Cannot write image to OpenCL buffer: buffer too small\n");
768 }
769 mapped = clEnqueueMapBuffer(opencl_ctx.
command_queue, dst_cl_buf,
770 CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
772 if (status != CL_SUCCESS) {
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 }
784 if (status != CL_SUCCESS) {
788 }
789 return 0;
790 }
791
793 cl_mem src_cl_buf, size_t cl_buffer_size)
794 {
795 int i,buffer_size = 0,ret = 0;
797 void *mapped;
798 cl_int status;
799 if ((unsigned int)plane_num > 8) {
801 }
802 for (i = 0; i < plane_num; i++) {
803 buffer_size += plane_size[i];
804 }
805 if (buffer_size > cl_buffer_size) {
807 "Cannot write image to CPU buffer: OpenCL buffer too small\n");
809 }
810 mapped = clEnqueueMapBuffer(opencl_ctx.
command_queue, src_cl_buf,
811 CL_TRUE, CL_MAP_READ, 0, buffer_size,
813
814 if (status != CL_SUCCESS) {
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 }
827 if (status != CL_SUCCESS) {
831 }
832 return 0;
833 }
834
837 {
838 int64_t ret = 0;
839 cl_int status;
840 cl_context_properties cps[3];
842
848
849 cps[0] = CL_CONTEXT_PLATFORM;
850 cps[1] = (cl_context_properties)platform;
851 cps[2] = 0;
854 if (status != CL_SUCCESS || !ext_opencl_env->
context) {
857 }
860 if (status != CL_SUCCESS || !ext_opencl_env->
command_queue) {
863 }
864 ret = benchmark(ext_opencl_env);
865 if (ret < 0)
872 clReleaseContext(ext_opencl_env->
context);
874 return ret;
875 }
const char const char void * val
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
#define AV_LOG_WARNING
Something somehow does not look correct.
#define LIBAVUTIL_VERSION_INT
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
void av_opt_set_defaults(void *s)
Set the values of all AVOption fields to their default values.
KernelCode kernel_code[MAX_KERNEL_CODE_NUM]
const char * av_opencl_errstr(cl_int status)
Get OpenCL error string.
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.
static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
static av_cold int end(AVCodecContext *avctx)
static const cl_device_type device_type[]
#define AV_LOG_VERBOSE
Detailed information.
int av_opencl_get_device_list(AVOpenCLDeviceList **device_list)
Get OpenCL device list.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
#define avpriv_atomic_ptr_cas
#define MAX_KERNEL_CODE_NUM
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static const OpenclErrorMsg opencl_err_msg[]
static int init_opencl_mtx(void)
simple assert() macros that are a bit more flexible than ISO C assert().
cl_platform_id platform_id
AVOpenCLDeviceList device_list
cl_platform_id platform_id
static const AVOption opencl_options[]
static void free_device_list(AVOpenCLDeviceList *device_list)
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
cl_program av_opencl_compile(const char *program_name, const char *build_opts)
compile specific OpenCL kernel source
int av_opencl_set_option(const char *key, const char *val)
Set option in the global OpenCL context.
int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
Create OpenCL buffer.
#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.
static const AVClass openclutils_class
cl_device_type device_type
static OpenclContext opencl_ctx
AVOpenCLPlatformNode ** platform_node
int av_opencl_register_kernel_code(const char *kernel_code)
Register kernel code.
void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env)
Free OpenCL external environment.
Describe the class of an AVClass context structure.
void av_opencl_free_option(void)
Free option values of the global OpenCL context.
AVOpenCLExternalEnv * av_opencl_alloc_external_env(void)
Allocate OpenCL external environment.
void av_opencl_buffer_release(cl_mem *cl_buf)
Release OpenCL buffer.
cl_command_queue command_queue
static int get_device_list(AVOpenCLDeviceList *device_list)
int is_user_created
if set to 1, the OpenCL environment was created by the user and passed as AVOpenCLExternalEnv when in...
const char * kernel_string
cl_command_queue av_opencl_get_command_queue(void)
get OpenCL command queue
void av_opt_free(void *obj)
Free all allocated objects in obj.
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.
void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
Free OpenCL device list.
void av_opencl_uninit(void)
Release OpenCL environment.
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
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.
int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
Initialize the run time OpenCL environment.
static void * av_mallocz_array(size_t nmemb, size_t size)
cl_device_type device_type
int av_opencl_get_option(const char *key, uint8_t **out_val)
Get option value from the global OpenCL context.
cl_command_queue command_queue
#define AVERROR_EXTERNAL
Generic error in an external library.
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
const char program_name[]
program name, defined by the program for show_version().
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.