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_PTHREADS
31
32 #include <pthread.h>
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
41 #endif
42
43 #define MAX_KERNEL_CODE_NUM 200
44
49
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 */
68 #if FF_API_OLD_OPENCL
73 #endif
78
79 #define OFFSET(x) offsetof(OpenclContext, x)
80
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
95 .log_level_offset_offset = offsetof(
OpenclContext, log_offset),
96 .parent_log_context_offset = offsetof(
OpenclContext, log_ctx),
97 };
98
100
101 static const cl_device_type
device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU};
102
107
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
170 {
171 int 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
180 {
181 int i, j;
182 if (!device_list)
183 return;
186 continue;
189 }
192 }
195 }
196
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;
205 status = clGetPlatformIDs(0, NULL, &device_list->
platform_num);
206 if (status != CL_SUCCESS) {
210 }
212 if (!platform_ids)
214 status = clGetPlatformIDs(device_list->
platform_num, platform_ids, NULL);
215 if (status != CL_SUCCESS) {
220 }
225 }
227 if (!devices_num) {
230 }
236 }
238 status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
241 total_devices_num = 0;
245 total_devices_num += devices_num[j];
246 }
251 }
253 if (devices_num[j]) {
254 device_ids =
av_mallocz(devices_num[j] *
sizeof(cl_device_id));
255 if (!device_ids) {
258 }
260 devices_num[j], device_ids, NULL);
261 if (status != CL_SUCCESS) {
265 continue;
266 }
267 for (k = 0; k < devices_num[j]; k++) {
273 }
277 status = clGetDeviceInfo(device_node->
device_id, CL_DEVICE_NAME,
279 NULL);
280 if (status != CL_SUCCESS) {
283 continue;
284 }
286 }
288 }
289 }
290 }
295 if (ret < 0)
298 }
299
301 {
304 if (!(*device_list)) {
307 }
309 if (ret < 0) {
314 }
316 }
317
319 {
322 }
323
325 {
331 }
335 }
336
338 {
341 ret =
av_opt_get(&opencl_ctx, key, 0, out_val);
344 }
345
347 {
348 /*FIXME: free openclutils context*/
352 }
353
355 {
357 if (!ext) {
359 "Could not malloc external opencl environment data space\n");
360 }
361 return ext;
362 }
363
365 {
367 }
368
370 {
375 "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
379 }
384 }
385 }
392 }
393
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
406 // identify a program using a unique name within the kernel source
411 kernel_code_idx = i;
412 break;
413 }
414 }
415 if (!kernel_source) {
417 "Unable to find OpenCL kernel source '%s'\n", program_name);
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) {
425 "Unable to create OpenCL program '%s': %s\n", program_name,
av_opencl_errstr(status));
426 program = NULL;
428 }
429 status = clBuildProgram(program, 1, &(opencl_ctx.
device_id), build_opts, NULL, NULL);
430 if (status != CL_SUCCESS) {
432 "Compilation failed with OpenCL program: %s\n", program_name);
433 program = NULL;
435 }
436
440 return program;
441 }
442
444 {
446 }
447
448 #if FF_API_OLD_OPENCL
450 {
451 av_log(&opencl_ctx,
AV_LOG_ERROR,
"Could not create OpenCL kernel %s, please update libavfilter.\n", kernel_name);
453 }
454
456 {
457 av_log(&opencl_ctx,
AV_LOG_ERROR,
"Could not release OpenCL kernel, please update libavfilter.\n");
458 }
459 #endif
460
462 {
463 cl_int status;
464 cl_context_properties cps[3];
467
468 if (ext_opencl_env) {
470 return 0;
477 } else {
481 if (ret < 0) {
483 }
484 }
489 }
491 av_log(opencl_ctx,
AV_LOG_ERROR,
"No devices in user specific platform with index %d\n",
494 }
496 } else {
497 /* get a usable platform by default*/
502 break;
503 }
504 }
505 }
509 }
510 /* get a usable device*/
514 "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->
platform_idx);
516 }
517 } else {
519 }
520
524
525 /*
526 * Use available platform.
527 */
531 cps[0] = CL_CONTEXT_PLATFORM;
532 cps[1] = (cl_context_properties)opencl_ctx->
platform_id;
533 cps[2] = 0;
534
536 NULL, NULL, &status);
537 if (status != CL_SUCCESS) {
539 "Could not get OpenCL context from device type: %s\n",
av_opencl_errstr(status));
541 }
543 0, &status);
544 if (status != CL_SUCCESS) {
548 }
549 }
550 }
552 }
553
555 {
562 }
564 if (ret < 0)
568 "No kernel code is registered, compile kernel file failed\n");
571 }
572 }
577 }
578
580 {
581 cl_int status;
590 if (status != CL_SUCCESS) {
593 }
595 }
597 status = clReleaseContext(opencl_ctx.
context);
598 if (status != CL_SUCCESS) {
601 }
603 }
607 av_opt_free(&opencl_ctx);
//FIXME: free openclutils context
609 }
610
612 {
613 cl_int status;
614 *cl_buf = clCreateBuffer(opencl_ctx.
context, flags, cl_buf_size, host_ptr, &status);
615 if (status != CL_SUCCESS) {
618 }
619 return 0;
620 }
621
623 {
624 cl_int status = 0;
625 if (!cl_buf)
626 return;
627 status = clReleaseMemObject(*cl_buf);
628 if (status != CL_SUCCESS) {
631 }
632 memset(cl_buf, 0, sizeof(*cl_buf));
633 }
634
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) {
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) {
654 }
655 return 0;
656 }
657
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) {
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) {
677 }
678 return 0;
679 }
680
682 uint8_t **src_data,
int *plane_size,
int plane_num)
683 {
684 int i, buffer_size = 0;
686 cl_int status;
687 void *mapped;
688 if ((unsigned int)plane_num > 8) {
690 }
691 for (i = 0;i < plane_num;i++) {
692 buffer_size += plane_size[i];
693 }
694 if (buffer_size > cl_buffer_size) {
696 "Cannot write image to OpenCL buffer: buffer too small\n");
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) {
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) {
718 }
719 return 0;
720 }
721
723 cl_mem src_cl_buf, size_t cl_buffer_size)
724 {
725 int i,buffer_size = 0,
ret = 0;
727 void *mapped;
728 cl_int status;
729 if ((unsigned int)plane_num > 8) {
731 }
732 for (i = 0; i < plane_num; i++) {
733 buffer_size += plane_size[i];
734 }
735 if (buffer_size > cl_buffer_size) {
737 "Cannot write image to CPU buffer: OpenCL buffer too small\n");
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) {
748 }
749 temp = mapped;
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) {
761 }
762 return 0;
763 }
764
767 {
769 cl_int status;
770 cl_context_properties cps[3];
772
778
779 cps[0] = CL_CONTEXT_PLATFORM;
780 cps[1] = (cl_context_properties)platform;
781 cps[2] = 0;
783 NULL, NULL, &status);
784 if (status != CL_SUCCESS || !ext_opencl_env->
context) {
787 }
790 if (status != CL_SUCCESS || !ext_opencl_env->
command_queue) {
793 }
794 ret = benchmark(ext_opencl_env);
795 if (ret < 0)
802 clReleaseContext(ext_opencl_env->
context);
805 }