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>
7 * This file is part of FFmpeg.
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.
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.
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
34 #include "compat/w32pthreads.h"
36 #include "compat/os2threads.h"
40 static volatile pthread_mutex_t
*atomic_opencl_lock
= NULL
;
41 #define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock)
42 #define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock)
48 #define MAX_KERNEL_CODE_NUM 200
52 const char *kernel_string
;
62 * if set to 1, the OpenCL environment was created by the user and
63 * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
68 cl_platform_id platform_id
;
69 cl_device_type device_type
;
71 cl_device_id device_id
;
72 cl_command_queue command_queue
;
76 cl_program programs
[MAX_KERNEL_CODE_NUM
];
79 int kernel_code_count
;
80 KernelCode kernel_code
[MAX_KERNEL_CODE_NUM
];
81 AVOpenCLDeviceList device_list
;
84 #define OFFSET(x) offsetof(OpenclContext, x)
86 static const AVOption opencl_options
[] = {
87 { "platform_idx", "set platform index value", OFFSET(platform_idx
), AV_OPT_TYPE_INT
, {.i64
=-1}, -1, INT_MAX
},
88 { "device_idx", "set device index value", OFFSET(device_idx
), AV_OPT_TYPE_INT
, {.i64
=-1}, -1, INT_MAX
},
90 { "build_options", "build options of opencl", OFFSET(build_options
), AV_OPT_TYPE_STRING
, {.str
="-I."}, CHAR_MIN
, CHAR_MAX
},
95 static const AVClass openclutils_class
= {
96 .class_name
= "OPENCLUTILS",
97 .option
= opencl_options
,
98 .item_name
= av_default_item_name
,
99 .version
= LIBAVUTIL_VERSION_INT
,
100 .log_level_offset_offset
= offsetof(OpenclContext
, log_offset
),
101 .parent_log_context_offset
= offsetof(OpenclContext
, log_ctx
),
104 static OpenclContext opencl_ctx
= {&openclutils_class
};
106 static const cl_device_type device_type
[] = {CL_DEVICE_TYPE_GPU
, CL_DEVICE_TYPE_CPU
};
113 static const OpenclErrorMsg opencl_err_msg
[] = {
114 {CL_DEVICE_NOT_FOUND
, "DEVICE NOT FOUND"},
115 {CL_DEVICE_NOT_AVAILABLE
, "DEVICE NOT AVAILABLE"},
116 {CL_COMPILER_NOT_AVAILABLE
, "COMPILER NOT AVAILABLE"},
117 {CL_MEM_OBJECT_ALLOCATION_FAILURE
, "MEM OBJECT ALLOCATION FAILURE"},
118 {CL_OUT_OF_RESOURCES
, "OUT OF RESOURCES"},
119 {CL_OUT_OF_HOST_MEMORY
, "OUT OF HOST MEMORY"},
120 {CL_PROFILING_INFO_NOT_AVAILABLE
, "PROFILING INFO NOT AVAILABLE"},
121 {CL_MEM_COPY_OVERLAP
, "MEM COPY OVERLAP"},
122 {CL_IMAGE_FORMAT_MISMATCH
, "IMAGE FORMAT MISMATCH"},
123 {CL_IMAGE_FORMAT_NOT_SUPPORTED
, "IMAGE FORMAT NOT_SUPPORTED"},
124 {CL_BUILD_PROGRAM_FAILURE
, "BUILD PROGRAM FAILURE"},
125 {CL_MAP_FAILURE
, "MAP FAILURE"},
126 {CL_MISALIGNED_SUB_BUFFER_OFFSET
, "MISALIGNED SUB BUFFER OFFSET"},
127 {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST
, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
128 {CL_COMPILE_PROGRAM_FAILURE
, "COMPILE PROGRAM FAILURE"},
129 {CL_LINKER_NOT_AVAILABLE
, "LINKER NOT AVAILABLE"},
130 {CL_LINK_PROGRAM_FAILURE
, "LINK PROGRAM FAILURE"},
131 {CL_DEVICE_PARTITION_FAILED
, "DEVICE PARTITION FAILED"},
132 {CL_KERNEL_ARG_INFO_NOT_AVAILABLE
, "KERNEL ARG INFO NOT AVAILABLE"},
133 {CL_INVALID_VALUE
, "INVALID VALUE"},
134 {CL_INVALID_DEVICE_TYPE
, "INVALID DEVICE TYPE"},
135 {CL_INVALID_PLATFORM
, "INVALID PLATFORM"},
136 {CL_INVALID_DEVICE
, "INVALID DEVICE"},
137 {CL_INVALID_CONTEXT
, "INVALID CONTEXT"},
138 {CL_INVALID_QUEUE_PROPERTIES
, "INVALID QUEUE PROPERTIES"},
139 {CL_INVALID_COMMAND_QUEUE
, "INVALID COMMAND QUEUE"},
140 {CL_INVALID_HOST_PTR
, "INVALID HOST PTR"},
141 {CL_INVALID_MEM_OBJECT
, "INVALID MEM OBJECT"},
142 {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR
, "INVALID IMAGE FORMAT DESCRIPTOR"},
143 {CL_INVALID_IMAGE_SIZE
, "INVALID IMAGE SIZE"},
144 {CL_INVALID_SAMPLER
, "INVALID SAMPLER"},
145 {CL_INVALID_BINARY
, "INVALID BINARY"},
146 {CL_INVALID_BUILD_OPTIONS
, "INVALID BUILD OPTIONS"},
147 {CL_INVALID_PROGRAM
, "INVALID PROGRAM"},
148 {CL_INVALID_PROGRAM_EXECUTABLE
, "INVALID PROGRAM EXECUTABLE"},
149 {CL_INVALID_KERNEL_NAME
, "INVALID KERNEL NAME"},
150 {CL_INVALID_KERNEL_DEFINITION
, "INVALID KERNEL DEFINITION"},
151 {CL_INVALID_KERNEL
, "INVALID KERNEL"},
152 {CL_INVALID_ARG_INDEX
, "INVALID ARG INDEX"},
153 {CL_INVALID_ARG_VALUE
, "INVALID ARG VALUE"},
154 {CL_INVALID_ARG_SIZE
, "INVALID ARG_SIZE"},
155 {CL_INVALID_KERNEL_ARGS
, "INVALID KERNEL ARGS"},
156 {CL_INVALID_WORK_DIMENSION
, "INVALID WORK DIMENSION"},
157 {CL_INVALID_WORK_GROUP_SIZE
, "INVALID WORK GROUP SIZE"},
158 {CL_INVALID_WORK_ITEM_SIZE
, "INVALID WORK ITEM SIZE"},
159 {CL_INVALID_GLOBAL_OFFSET
, "INVALID GLOBAL OFFSET"},
160 {CL_INVALID_EVENT_WAIT_LIST
, "INVALID EVENT WAIT LIST"},
161 {CL_INVALID_EVENT
, "INVALID EVENT"},
162 {CL_INVALID_OPERATION
, "INVALID OPERATION"},
163 {CL_INVALID_GL_OBJECT
, "INVALID GL OBJECT"},
164 {CL_INVALID_BUFFER_SIZE
, "INVALID BUFFER SIZE"},
165 {CL_INVALID_MIP_LEVEL
, "INVALID MIP LEVEL"},
166 {CL_INVALID_GLOBAL_WORK_SIZE
, "INVALID GLOBAL WORK SIZE"},
167 {CL_INVALID_PROPERTY
, "INVALID PROPERTY"},
168 {CL_INVALID_IMAGE_DESCRIPTOR
, "INVALID IMAGE DESCRIPTOR"},
169 {CL_INVALID_COMPILER_OPTIONS
, "INVALID COMPILER OPTIONS"},
170 {CL_INVALID_LINKER_OPTIONS
, "INVALID LINKER OPTIONS"},
171 {CL_INVALID_DEVICE_PARTITION_COUNT
, "INVALID DEVICE PARTITION COUNT"},
174 const char *av_opencl_errstr(cl_int status
)
177 for (i
= 0; i
< FF_ARRAY_ELEMS(opencl_err_msg
); i
++) {
178 if (opencl_err_msg
[i
].err_code
== status
)
179 return opencl_err_msg
[i
].err_str
;
181 return "unknown error";
184 static void free_device_list(AVOpenCLDeviceList
*device_list
)
189 for (i
= 0; i
< device_list
->platform_num
; i
++) {
190 if (!device_list
->platform_node
[i
])
192 for (j
= 0; j
< device_list
->platform_node
[i
]->device_num
; j
++) {
193 av_freep(&(device_list
->platform_node
[i
]->device_node
[j
]));
195 av_freep(&device_list
->platform_node
[i
]->device_node
);
196 av_freep(&device_list
->platform_node
[i
]);
198 av_freep(&device_list
->platform_node
);
199 device_list
->platform_num
= 0;
202 static int get_device_list(AVOpenCLDeviceList
*device_list
)
205 int i
, j
, k
, device_num
, total_devices_num
, ret
= 0;
207 cl_platform_id
*platform_ids
= NULL
;
208 cl_device_id
*device_ids
= NULL
;
209 AVOpenCLDeviceNode
*device_node
= NULL
;
210 status
= clGetPlatformIDs(0, NULL
, &device_list
->platform_num
);
211 if (status
!= CL_SUCCESS
) {
212 av_log(&opencl_ctx
, AV_LOG_ERROR
,
213 "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status
));
214 return AVERROR_EXTERNAL
;
216 platform_ids
= av_mallocz_array(device_list
->platform_num
, sizeof(cl_platform_id
));
218 return AVERROR(ENOMEM
);
219 status
= clGetPlatformIDs(device_list
->platform_num
, platform_ids
, NULL
);
220 if (status
!= CL_SUCCESS
) {
221 av_log(&opencl_ctx
, AV_LOG_ERROR
,
222 "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status
));
223 ret
= AVERROR_EXTERNAL
;
226 device_list
->platform_node
= av_mallocz_array(device_list
->platform_num
, sizeof(AVOpenCLPlatformNode
*));
227 if (!device_list
->platform_node
) {
228 ret
= AVERROR(ENOMEM
);
231 devices_num
= av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type
));
233 ret
= AVERROR(ENOMEM
);
236 for (i
= 0; i
< device_list
->platform_num
; i
++) {
237 device_list
->platform_node
[i
] = av_mallocz(sizeof(AVOpenCLPlatformNode
));
238 if (!device_list
->platform_node
[i
]) {
239 ret
= AVERROR(ENOMEM
);
242 device_list
->platform_node
[i
]->platform_id
= platform_ids
[i
];
243 status
= clGetPlatformInfo(platform_ids
[i
], CL_PLATFORM_VENDOR
,
244 sizeof(device_list
->platform_node
[i
]->platform_name
),
245 device_list
->platform_node
[i
]->platform_name
, NULL
);
246 total_devices_num
= 0;
247 for (j
= 0; j
< FF_ARRAY_ELEMS(device_type
); j
++) {
248 status
= clGetDeviceIDs(device_list
->platform_node
[i
]->platform_id
,
249 device_type
[j
], 0, NULL
, &devices_num
[j
]);
250 total_devices_num
+= devices_num
[j
];
252 device_list
->platform_node
[i
]->device_node
= av_mallocz_array(total_devices_num
, sizeof(AVOpenCLDeviceNode
*));
253 if (!device_list
->platform_node
[i
]->device_node
) {
254 ret
= AVERROR(ENOMEM
);
257 for (j
= 0; j
< FF_ARRAY_ELEMS(device_type
); j
++) {
258 if (devices_num
[j
]) {
259 device_ids
= av_mallocz_array(devices_num
[j
], sizeof(cl_device_id
));
261 ret
= AVERROR(ENOMEM
);
264 status
= clGetDeviceIDs(device_list
->platform_node
[i
]->platform_id
, device_type
[j
],
265 devices_num
[j
], device_ids
, NULL
);
266 if (status
!= CL_SUCCESS
) {
267 av_log(&opencl_ctx
, AV_LOG_WARNING
,
268 "Could not get device ID: %s:\n", av_opencl_errstr(status
));
269 av_freep(&device_ids
);
272 for (k
= 0; k
< devices_num
[j
]; k
++) {
273 device_num
= device_list
->platform_node
[i
]->device_num
;
274 device_list
->platform_node
[i
]->device_node
[device_num
] = av_mallocz(sizeof(AVOpenCLDeviceNode
));
275 if (!device_list
->platform_node
[i
]->device_node
[device_num
]) {
276 ret
= AVERROR(ENOMEM
);
279 device_node
= device_list
->platform_node
[i
]->device_node
[device_num
];
280 device_node
->device_id
= device_ids
[k
];
281 device_node
->device_type
= device_type
[j
];
282 status
= clGetDeviceInfo(device_node
->device_id
, CL_DEVICE_NAME
,
283 sizeof(device_node
->device_name
), device_node
->device_name
,
285 if (status
!= CL_SUCCESS
) {
286 av_log(&opencl_ctx
, AV_LOG_WARNING
,
287 "Could not get device name: %s\n", av_opencl_errstr(status
));
290 device_list
->platform_node
[i
]->device_num
++;
292 av_freep(&device_ids
);
297 av_freep(&platform_ids
);
298 av_freep(&devices_num
);
299 av_freep(&device_ids
);
301 free_device_list(device_list
);
305 int av_opencl_get_device_list(AVOpenCLDeviceList
**device_list
)
308 *device_list
= av_mallocz(sizeof(AVOpenCLDeviceList
));
309 if (!(*device_list
)) {
310 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Could not allocate opencl device list\n");
311 return AVERROR(ENOMEM
);
313 ret
= get_device_list(*device_list
);
315 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Could not get device list from environment\n");
316 free_device_list(*device_list
);
317 av_freep(device_list
);
323 void av_opencl_free_device_list(AVOpenCLDeviceList
**device_list
)
325 free_device_list(*device_list
);
326 av_freep(device_list
);
329 static inline int init_opencl_mtx(void)
332 if (!atomic_opencl_lock
) {
334 pthread_mutex_t
*tmp
= av_malloc(sizeof(pthread_mutex_t
));
336 return AVERROR(ENOMEM
);
337 if ((err
= pthread_mutex_init(tmp
, NULL
))) {
341 if (avpriv_atomic_ptr_cas(&atomic_opencl_lock
, NULL
, tmp
)) {
342 pthread_mutex_destroy(tmp
);
350 int av_opencl_set_option(const char *key
, const char *val
)
352 int ret
= init_opencl_mtx( );
356 if (!opencl_ctx
.opt_init_flag
) {
357 av_opt_set_defaults(&opencl_ctx
);
358 opencl_ctx
.opt_init_flag
= 1;
360 ret
= av_opt_set(&opencl_ctx
, key
, val
, 0);
365 int av_opencl_get_option(const char *key
, uint8_t **out_val
)
369 ret
= av_opt_get(&opencl_ctx
, key
, 0, out_val
);
374 void av_opencl_free_option(void)
376 /*FIXME: free openclutils context*/
378 av_opt_free(&opencl_ctx
);
382 AVOpenCLExternalEnv
*av_opencl_alloc_external_env(void)
384 AVOpenCLExternalEnv
*ext
= av_mallocz(sizeof(AVOpenCLExternalEnv
));
386 av_log(&opencl_ctx
, AV_LOG_ERROR
,
387 "Could not malloc external opencl environment data space\n");
392 void av_opencl_free_external_env(AVOpenCLExternalEnv
**ext_opencl_env
)
394 av_freep(ext_opencl_env
);
397 int av_opencl_register_kernel_code(const char *kernel_code
)
399 int i
, ret
= init_opencl_mtx( );
403 if (opencl_ctx
.kernel_code_count
>= MAX_KERNEL_CODE_NUM
) {
404 av_log(&opencl_ctx
, AV_LOG_ERROR
,
405 "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
406 MAX_KERNEL_CODE_NUM
);
407 ret
= AVERROR(EINVAL
);
410 for (i
= 0; i
< opencl_ctx
.kernel_code_count
; i
++) {
411 if (opencl_ctx
.kernel_code
[i
].kernel_string
== kernel_code
) {
412 av_log(&opencl_ctx
, AV_LOG_WARNING
, "Same kernel code has been registered\n");
416 opencl_ctx
.kernel_code
[opencl_ctx
.kernel_code_count
].kernel_string
= kernel_code
;
417 opencl_ctx
.kernel_code
[opencl_ctx
.kernel_code_count
].is_compiled
= 0;
418 opencl_ctx
.kernel_code_count
++;
424 cl_program
av_opencl_compile(const char *program_name
, const char *build_opts
)
428 int kernel_code_idx
= 0;
429 const char *kernel_source
;
430 size_t kernel_code_len
;
432 cl_program program
= NULL
;
435 for (i
= 0; i
< opencl_ctx
.kernel_code_count
; i
++) {
436 // identify a program using a unique name within the kernel source
437 ptr
= av_stristr(opencl_ctx
.kernel_code
[i
].kernel_string
, program_name
);
438 if (ptr
&& !opencl_ctx
.kernel_code
[i
].is_compiled
) {
439 kernel_source
= opencl_ctx
.kernel_code
[i
].kernel_string
;
440 kernel_code_len
= strlen(opencl_ctx
.kernel_code
[i
].kernel_string
);
445 if (!kernel_source
) {
446 av_log(&opencl_ctx
, AV_LOG_ERROR
,
447 "Unable to find OpenCL kernel source '%s'\n", program_name
);
451 /* create a CL program from kernel source */
452 program
= clCreateProgramWithSource(opencl_ctx
.context
, 1, &kernel_source
, &kernel_code_len
, &status
);
453 if(status
!= CL_SUCCESS
) {
454 av_log(&opencl_ctx
, AV_LOG_ERROR
,
455 "Unable to create OpenCL program '%s': %s\n", program_name
, av_opencl_errstr(status
));
459 status
= clBuildProgram(program
, 1, &(opencl_ctx
.device_id
), build_opts
, NULL
, NULL
);
460 if (status
!= CL_SUCCESS
) {
461 av_log(&opencl_ctx
, AV_LOG_ERROR
,
462 "Compilation failed with OpenCL program: %s\n", program_name
);
467 opencl_ctx
.kernel_code
[kernel_code_idx
].is_compiled
= 1;
473 cl_command_queue
av_opencl_get_command_queue(void)
475 return opencl_ctx
.command_queue
;
478 #if FF_API_OLD_OPENCL
479 int av_opencl_create_kernel(AVOpenCLKernelEnv
*env
, const char *kernel_name
)
481 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Could not create OpenCL kernel %s, please update libavfilter.\n", kernel_name
);
482 return AVERROR(EINVAL
);
485 void av_opencl_release_kernel(AVOpenCLKernelEnv
*env
)
487 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Could not release OpenCL kernel, please update libavfilter.\n");
491 static int init_opencl_env(OpenclContext
*opencl_ctx
, AVOpenCLExternalEnv
*ext_opencl_env
)
494 cl_context_properties cps
[3];
496 AVOpenCLDeviceNode
*device_node
= NULL
;
498 if (ext_opencl_env
) {
499 if (opencl_ctx
->is_user_created
)
501 opencl_ctx
->platform_id
= ext_opencl_env
->platform_id
;
502 opencl_ctx
->is_user_created
= 1;
503 opencl_ctx
->command_queue
= ext_opencl_env
->command_queue
;
504 opencl_ctx
->context
= ext_opencl_env
->context
;
505 opencl_ctx
->device_id
= ext_opencl_env
->device_id
;
506 opencl_ctx
->device_type
= ext_opencl_env
->device_type
;
508 if (!opencl_ctx
->is_user_created
) {
509 if (!opencl_ctx
->device_list
.platform_num
) {
510 ret
= get_device_list(&opencl_ctx
->device_list
);
515 if (opencl_ctx
->platform_idx
>= 0) {
516 if (opencl_ctx
->device_list
.platform_num
< opencl_ctx
->platform_idx
+ 1) {
517 av_log(opencl_ctx
, AV_LOG_ERROR
, "User set platform index not exist\n");
518 return AVERROR(EINVAL
);
520 if (!opencl_ctx
->device_list
.platform_node
[opencl_ctx
->platform_idx
]->device_num
) {
521 av_log(opencl_ctx
, AV_LOG_ERROR
, "No devices in user specific platform with index %d\n",
522 opencl_ctx
->platform_idx
);
523 return AVERROR(EINVAL
);
525 opencl_ctx
->platform_id
= opencl_ctx
->device_list
.platform_node
[opencl_ctx
->platform_idx
]->platform_id
;
527 /* get a usable platform by default*/
528 for (i
= 0; i
< opencl_ctx
->device_list
.platform_num
; i
++) {
529 if (opencl_ctx
->device_list
.platform_node
[i
]->device_num
) {
530 opencl_ctx
->platform_id
= opencl_ctx
->device_list
.platform_node
[i
]->platform_id
;
531 opencl_ctx
->platform_idx
= i
;
536 if (!opencl_ctx
->platform_id
) {
537 av_log(opencl_ctx
, AV_LOG_ERROR
, "Could not get OpenCL platforms\n");
538 return AVERROR_EXTERNAL
;
540 /* get a usable device*/
541 if (opencl_ctx
->device_idx
>= 0) {
542 if (opencl_ctx
->device_list
.platform_node
[opencl_ctx
->platform_idx
]->device_num
< opencl_ctx
->device_idx
+ 1) {
543 av_log(opencl_ctx
, AV_LOG_ERROR
,
544 "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx
->platform_idx
);
545 return AVERROR(EINVAL
);
548 opencl_ctx
->device_idx
= 0;
551 device_node
= opencl_ctx
->device_list
.platform_node
[opencl_ctx
->platform_idx
]->device_node
[opencl_ctx
->device_idx
];
552 opencl_ctx
->device_id
= device_node
->device_id
;
553 opencl_ctx
->device_type
= device_node
->device_type
;
556 * Use available platform.
558 av_log(opencl_ctx
, AV_LOG_VERBOSE
, "Platform Name: %s, Device Name: %s\n",
559 opencl_ctx
->device_list
.platform_node
[opencl_ctx
->platform_idx
]->platform_name
,
560 device_node
->device_name
);
561 cps
[0] = CL_CONTEXT_PLATFORM
;
562 cps
[1] = (cl_context_properties
)opencl_ctx
->platform_id
;
565 opencl_ctx
->context
= clCreateContextFromType(cps
, opencl_ctx
->device_type
,
566 NULL
, NULL
, &status
);
567 if (status
!= CL_SUCCESS
) {
568 av_log(opencl_ctx
, AV_LOG_ERROR
,
569 "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status
));
570 return AVERROR_EXTERNAL
;
572 opencl_ctx
->command_queue
= clCreateCommandQueue(opencl_ctx
->context
, opencl_ctx
->device_id
,
574 if (status
!= CL_SUCCESS
) {
575 av_log(opencl_ctx
, AV_LOG_ERROR
,
576 "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status
));
577 return AVERROR_EXTERNAL
;
584 int av_opencl_init(AVOpenCLExternalEnv
*ext_opencl_env
)
586 int ret
= init_opencl_mtx( );
590 if (!opencl_ctx
.init_count
) {
591 if (!opencl_ctx
.opt_init_flag
) {
592 av_opt_set_defaults(&opencl_ctx
);
593 opencl_ctx
.opt_init_flag
= 1;
595 ret
= init_opencl_env(&opencl_ctx
, ext_opencl_env
);
598 if (opencl_ctx
.kernel_code_count
<= 0) {
599 av_log(&opencl_ctx
, AV_LOG_ERROR
,
600 "No kernel code is registered, compile kernel file failed\n");
601 ret
= AVERROR(EINVAL
);
605 opencl_ctx
.init_count
++;
611 void av_opencl_uninit(void)
615 opencl_ctx
.init_count
--;
616 if (opencl_ctx
.is_user_created
)
618 if (opencl_ctx
.init_count
> 0)
620 if (opencl_ctx
.command_queue
) {
621 status
= clReleaseCommandQueue(opencl_ctx
.command_queue
);
622 if (status
!= CL_SUCCESS
) {
623 av_log(&opencl_ctx
, AV_LOG_ERROR
,
624 "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status
));
626 opencl_ctx
.command_queue
= NULL
;
628 if (opencl_ctx
.context
) {
629 status
= clReleaseContext(opencl_ctx
.context
);
630 if (status
!= CL_SUCCESS
) {
631 av_log(&opencl_ctx
, AV_LOG_ERROR
,
632 "Could not release OpenCL context: %s\n", av_opencl_errstr(status
));
634 opencl_ctx
.context
= NULL
;
636 free_device_list(&opencl_ctx
.device_list
);
638 if (opencl_ctx
.init_count
<= 0)
639 av_opt_free(&opencl_ctx
); //FIXME: free openclutils context
643 int av_opencl_buffer_create(cl_mem
*cl_buf
, size_t cl_buf_size
, int flags
, void *host_ptr
)
646 *cl_buf
= clCreateBuffer(opencl_ctx
.context
, flags
, cl_buf_size
, host_ptr
, &status
);
647 if (status
!= CL_SUCCESS
) {
648 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status
));
649 return AVERROR_EXTERNAL
;
654 void av_opencl_buffer_release(cl_mem
*cl_buf
)
659 status
= clReleaseMemObject(*cl_buf
);
660 if (status
!= CL_SUCCESS
) {
661 av_log(&opencl_ctx
, AV_LOG_ERROR
,
662 "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status
));
664 memset(cl_buf
, 0, sizeof(*cl_buf
));
667 int av_opencl_buffer_write(cl_mem dst_cl_buf
, uint8_t *src_buf
, size_t buf_size
)
670 void *mapped
= clEnqueueMapBuffer(opencl_ctx
.command_queue
, dst_cl_buf
,
671 CL_TRUE
, CL_MAP_WRITE
, 0, sizeof(uint8_t) * buf_size
,
672 0, NULL
, NULL
, &status
);
674 if (status
!= CL_SUCCESS
) {
675 av_log(&opencl_ctx
, AV_LOG_ERROR
,
676 "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status
));
677 return AVERROR_EXTERNAL
;
679 memcpy(mapped
, src_buf
, buf_size
);
681 status
= clEnqueueUnmapMemObject(opencl_ctx
.command_queue
, dst_cl_buf
, mapped
, 0, NULL
, NULL
);
682 if (status
!= CL_SUCCESS
) {
683 av_log(&opencl_ctx
, AV_LOG_ERROR
,
684 "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status
));
685 return AVERROR_EXTERNAL
;
690 int av_opencl_buffer_read(uint8_t *dst_buf
, cl_mem src_cl_buf
, size_t buf_size
)
693 void *mapped
= clEnqueueMapBuffer(opencl_ctx
.command_queue
, src_cl_buf
,
694 CL_TRUE
, CL_MAP_READ
, 0, buf_size
,
695 0, NULL
, NULL
, &status
);
697 if (status
!= CL_SUCCESS
) {
698 av_log(&opencl_ctx
, AV_LOG_ERROR
,
699 "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status
));
700 return AVERROR_EXTERNAL
;
702 memcpy(dst_buf
, mapped
, buf_size
);
704 status
= clEnqueueUnmapMemObject(opencl_ctx
.command_queue
, src_cl_buf
, mapped
, 0, NULL
, NULL
);
705 if (status
!= CL_SUCCESS
) {
706 av_log(&opencl_ctx
, AV_LOG_ERROR
,
707 "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status
));
708 return AVERROR_EXTERNAL
;
713 int av_opencl_buffer_write_image(cl_mem dst_cl_buf
, size_t cl_buffer_size
, int dst_cl_offset
,
714 uint8_t **src_data
, int *plane_size
, int plane_num
)
716 int i
, buffer_size
= 0;
720 if ((unsigned int)plane_num
> 8) {
721 return AVERROR(EINVAL
);
723 for (i
= 0;i
< plane_num
;i
++) {
724 buffer_size
+= plane_size
[i
];
726 if (buffer_size
> cl_buffer_size
) {
727 av_log(&opencl_ctx
, AV_LOG_ERROR
,
728 "Cannot write image to OpenCL buffer: buffer too small\n");
729 return AVERROR(EINVAL
);
731 mapped
= clEnqueueMapBuffer(opencl_ctx
.command_queue
, dst_cl_buf
,
732 CL_TRUE
, CL_MAP_WRITE
, 0, buffer_size
+ dst_cl_offset
,
733 0, NULL
, NULL
, &status
);
734 if (status
!= CL_SUCCESS
) {
735 av_log(&opencl_ctx
, AV_LOG_ERROR
,
736 "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status
));
737 return AVERROR_EXTERNAL
;
740 temp
+= dst_cl_offset
;
741 for (i
= 0; i
< plane_num
; i
++) {
742 memcpy(temp
, src_data
[i
], plane_size
[i
]);
743 temp
+= plane_size
[i
];
745 status
= clEnqueueUnmapMemObject(opencl_ctx
.command_queue
, dst_cl_buf
, mapped
, 0, NULL
, NULL
);
746 if (status
!= CL_SUCCESS
) {
747 av_log(&opencl_ctx
, AV_LOG_ERROR
,
748 "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status
));
749 return AVERROR_EXTERNAL
;
754 int av_opencl_buffer_read_image(uint8_t **dst_data
, int *plane_size
, int plane_num
,
755 cl_mem src_cl_buf
, size_t cl_buffer_size
)
757 int i
,buffer_size
= 0,ret
= 0;
761 if ((unsigned int)plane_num
> 8) {
762 return AVERROR(EINVAL
);
764 for (i
= 0; i
< plane_num
; i
++) {
765 buffer_size
+= plane_size
[i
];
767 if (buffer_size
> cl_buffer_size
) {
768 av_log(&opencl_ctx
, AV_LOG_ERROR
,
769 "Cannot write image to CPU buffer: OpenCL buffer too small\n");
770 return AVERROR(EINVAL
);
772 mapped
= clEnqueueMapBuffer(opencl_ctx
.command_queue
, src_cl_buf
,
773 CL_TRUE
, CL_MAP_READ
, 0, buffer_size
,
774 0, NULL
, NULL
, &status
);
776 if (status
!= CL_SUCCESS
) {
777 av_log(&opencl_ctx
, AV_LOG_ERROR
,
778 "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status
));
779 return AVERROR_EXTERNAL
;
783 for (i
= 0; i
< plane_num
; i
++) {
784 memcpy(dst_data
[i
], temp
, plane_size
[i
]);
785 temp
+= plane_size
[i
];
788 status
= clEnqueueUnmapMemObject(opencl_ctx
.command_queue
, src_cl_buf
, mapped
, 0, NULL
, NULL
);
789 if (status
!= CL_SUCCESS
) {
790 av_log(&opencl_ctx
, AV_LOG_ERROR
,
791 "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status
));
792 return AVERROR_EXTERNAL
;
797 int64_t av_opencl_benchmark(AVOpenCLDeviceNode
*device_node
, cl_platform_id platform
,
798 int64_t (*benchmark
)(AVOpenCLExternalEnv
*ext_opencl_env
))
802 cl_context_properties cps
[3];
803 AVOpenCLExternalEnv
*ext_opencl_env
= NULL
;
805 ext_opencl_env
= av_opencl_alloc_external_env();
806 ext_opencl_env
->device_id
= device_node
->device_id
;
807 ext_opencl_env
->device_type
= device_node
->device_type
;
808 av_log(&opencl_ctx
, AV_LOG_VERBOSE
, "Performing test on OpenCL device %s\n",
809 device_node
->device_name
);
811 cps
[0] = CL_CONTEXT_PLATFORM
;
812 cps
[1] = (cl_context_properties
)platform
;
814 ext_opencl_env
->context
= clCreateContextFromType(cps
, ext_opencl_env
->device_type
,
815 NULL
, NULL
, &status
);
816 if (status
!= CL_SUCCESS
|| !ext_opencl_env
->context
) {
817 ret
= AVERROR_EXTERNAL
;
820 ext_opencl_env
->command_queue
= clCreateCommandQueue(ext_opencl_env
->context
,
821 ext_opencl_env
->device_id
, 0, &status
);
822 if (status
!= CL_SUCCESS
|| !ext_opencl_env
->command_queue
) {
823 ret
= AVERROR_EXTERNAL
;
826 ret
= benchmark(ext_opencl_env
);
828 av_log(&opencl_ctx
, AV_LOG_ERROR
, "Benchmark failed with OpenCL device %s\n",
829 device_node
->device_name
);
831 if (ext_opencl_env
->command_queue
)
832 clReleaseCommandQueue(ext_opencl_env
->command_queue
);
833 if (ext_opencl_env
->context
)
834 clReleaseContext(ext_opencl_env
->context
);
835 av_opencl_free_external_env(&ext_opencl_env
);