|
|
|
@ -1,7 +1,8 @@ |
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2012 Li Cao <li@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2012 Li Cao <li@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com> |
|
|
|
|
* Copyright (C) 2013 Lenny Wang <lwanghpc@gmail.com> |
|
|
|
|
* |
|
|
|
|
* This file is part of FFmpeg. |
|
|
|
|
* |
|
|
|
@ -39,8 +40,6 @@ static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER; |
|
|
|
|
#define UNLOCK_OPENCL |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_KERNEL_NUM 500 |
|
|
|
|
#define MAX_KERNEL_CODE_NUM 200 |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
@ -61,17 +60,19 @@ typedef struct { |
|
|
|
|
int is_user_created; |
|
|
|
|
int platform_idx; |
|
|
|
|
int device_idx; |
|
|
|
|
char *build_options; |
|
|
|
|
cl_platform_id platform_id; |
|
|
|
|
cl_device_type device_type; |
|
|
|
|
cl_context context; |
|
|
|
|
cl_device_id device_id; |
|
|
|
|
cl_command_queue command_queue; |
|
|
|
|
#if FF_API_OLD_OPENCL |
|
|
|
|
char *build_options; |
|
|
|
|
int program_count; |
|
|
|
|
cl_program programs[MAX_KERNEL_CODE_NUM]; |
|
|
|
|
int kernel_count; |
|
|
|
|
#endif |
|
|
|
|
int kernel_code_count; |
|
|
|
|
KernelCode kernel_code[MAX_KERNEL_CODE_NUM]; |
|
|
|
|
int kernel_count; |
|
|
|
|
AVOpenCLDeviceList device_list; |
|
|
|
|
} OpenclContext; |
|
|
|
|
|
|
|
|
@ -80,7 +81,9 @@ typedef struct { |
|
|
|
|
static const AVOption opencl_options[] = { |
|
|
|
|
{ "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, |
|
|
|
|
{ "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, |
|
|
|
|
#if FF_API_OLD_OPENCL |
|
|
|
|
{ "build_options", "build options of opencl", OFFSET(build_options), AV_OPT_TYPE_STRING, {.str="-I."}, CHAR_MIN, CHAR_MAX}, |
|
|
|
|
#endif |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -194,7 +197,7 @@ static void free_device_list(AVOpenCLDeviceList *device_list) |
|
|
|
|
static int get_device_list(AVOpenCLDeviceList *device_list) |
|
|
|
|
{ |
|
|
|
|
cl_int status; |
|
|
|
|
int i, j, k, device_num, total_devices_num,ret = 0; |
|
|
|
|
int i, j, k, device_num, total_devices_num, ret = 0; |
|
|
|
|
int *devices_num; |
|
|
|
|
cl_platform_id *platform_ids = NULL; |
|
|
|
|
cl_device_id *device_ids = NULL; |
|
|
|
@ -388,66 +391,72 @@ end: |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name) |
|
|
|
|
cl_program av_opencl_compile(const char *program_name, const char *build_opts) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
cl_int status; |
|
|
|
|
int i, ret = 0; |
|
|
|
|
int kernel_code_idx = 0; |
|
|
|
|
const char *kernel_source; |
|
|
|
|
size_t kernel_code_len; |
|
|
|
|
char* ptr = NULL; |
|
|
|
|
cl_program program = NULL; |
|
|
|
|
|
|
|
|
|
LOCK_OPENCL; |
|
|
|
|
if (strlen(kernel_name) + 1 > AV_OPENCL_MAX_KERNEL_NAME_SIZE) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Created kernel name %s is too long\n", kernel_name); |
|
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
|
for (i = 0; i < opencl_ctx.kernel_code_count; i++) { |
|
|
|
|
// identify a program using a unique name within the kernel source
|
|
|
|
|
ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name); |
|
|
|
|
if (ptr && !opencl_ctx.kernel_code[i].is_compiled) { |
|
|
|
|
kernel_source = opencl_ctx.kernel_code[i].kernel_string; |
|
|
|
|
kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string); |
|
|
|
|
kernel_code_idx = i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!kernel_source) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Unable to find OpenCL kernel source '%s'\n", program_name); |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
if (!env->kernel) { |
|
|
|
|
if (opencl_ctx.kernel_count >= MAX_KERNEL_NUM) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Could not create kernel with name '%s', maximum number of kernels %d already reached\n", |
|
|
|
|
kernel_name, MAX_KERNEL_NUM); |
|
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
if (opencl_ctx.program_count == 0) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Program count of OpenCL is 0, can not create kernel\n"); |
|
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
for (i = 0; i < opencl_ctx.program_count; i++) { |
|
|
|
|
env->kernel = clCreateKernel(opencl_ctx.programs[i], kernel_name, &status); |
|
|
|
|
if (status == CL_SUCCESS) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel: %s\n", av_opencl_errstr(status)); |
|
|
|
|
ret = AVERROR_EXTERNAL; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
opencl_ctx.kernel_count++; |
|
|
|
|
env->command_queue = opencl_ctx.command_queue; |
|
|
|
|
av_strlcpy(env->kernel_name, kernel_name, sizeof(env->kernel_name)); |
|
|
|
|
|
|
|
|
|
/* create a CL program from kernel source */ |
|
|
|
|
program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status); |
|
|
|
|
if(status != CL_SUCCESS) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status)); |
|
|
|
|
program = NULL; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL); |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Compilation failed with OpenCL program: %s\n", program_name); |
|
|
|
|
program = NULL; |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1; |
|
|
|
|
end: |
|
|
|
|
UNLOCK_OPENCL; |
|
|
|
|
return ret; |
|
|
|
|
return program; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cl_command_queue av_opencl_get_command_queue(void) |
|
|
|
|
{ |
|
|
|
|
return opencl_ctx.command_queue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if FF_API_OLD_OPENCL |
|
|
|
|
int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name) |
|
|
|
|
{ |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel %s, please update libavfilter.\n", kernel_name); |
|
|
|
|
return AVERROR(EINVAL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void av_opencl_release_kernel(AVOpenCLKernelEnv *env) |
|
|
|
|
{ |
|
|
|
|
cl_int status; |
|
|
|
|
LOCK_OPENCL; |
|
|
|
|
if (!env->kernel) |
|
|
|
|
goto end; |
|
|
|
|
status = clReleaseKernel(env->kernel); |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release kernel: %s\n", |
|
|
|
|
av_opencl_errstr(status)); |
|
|
|
|
} |
|
|
|
|
env->kernel = NULL; |
|
|
|
|
env->command_queue = NULL; |
|
|
|
|
env->kernel_name[0] = 0; |
|
|
|
|
opencl_ctx.kernel_count--; |
|
|
|
|
end: |
|
|
|
|
UNLOCK_OPENCL; |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release OpenCL kernel, please update libavfilter.\n"); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env) |
|
|
|
|
{ |
|
|
|
@ -542,49 +551,6 @@ static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_o |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int compile_kernel_file(OpenclContext *opencl_ctx) |
|
|
|
|
{ |
|
|
|
|
cl_int status; |
|
|
|
|
int i, kernel_code_count = 0; |
|
|
|
|
const char *kernel_code[MAX_KERNEL_CODE_NUM] = {NULL}; |
|
|
|
|
size_t kernel_code_len[MAX_KERNEL_CODE_NUM] = {0}; |
|
|
|
|
|
|
|
|
|
for (i = 0; i < opencl_ctx->kernel_code_count; i++) { |
|
|
|
|
if (!opencl_ctx->kernel_code[i].is_compiled) { |
|
|
|
|
kernel_code[kernel_code_count] = opencl_ctx->kernel_code[i].kernel_string; |
|
|
|
|
kernel_code_len[kernel_code_count] = strlen(opencl_ctx->kernel_code[i].kernel_string); |
|
|
|
|
opencl_ctx->kernel_code[i].is_compiled = 1; |
|
|
|
|
kernel_code_count++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!kernel_code_count) |
|
|
|
|
return 0; |
|
|
|
|
/* create a CL program using the kernel source */ |
|
|
|
|
opencl_ctx->programs[opencl_ctx->program_count] = clCreateProgramWithSource(opencl_ctx->context, |
|
|
|
|
kernel_code_count, |
|
|
|
|
kernel_code, |
|
|
|
|
kernel_code_len, |
|
|
|
|
&status); |
|
|
|
|
if(status != CL_SUCCESS) { |
|
|
|
|
av_log(opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Could not create OpenCL program with source code: %s\n", av_opencl_errstr(status)); |
|
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
|
} |
|
|
|
|
if (!opencl_ctx->programs[opencl_ctx->program_count]) { |
|
|
|
|
av_log(opencl_ctx, AV_LOG_ERROR, "Created program is NULL\n"); |
|
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
|
} |
|
|
|
|
status = clBuildProgram(opencl_ctx->programs[opencl_ctx->program_count], 1, &(opencl_ctx->device_id), |
|
|
|
|
opencl_ctx->build_options, NULL, NULL); |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
|
av_log(opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Could not compile OpenCL kernel: %s\n", av_opencl_errstr(status)); |
|
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
|
} |
|
|
|
|
opencl_ctx->program_count++; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env) |
|
|
|
|
{ |
|
|
|
|
int ret = 0; |
|
|
|
@ -597,18 +563,14 @@ int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env) |
|
|
|
|
ret = init_opencl_env(&opencl_ctx, ext_opencl_env); |
|
|
|
|
if (ret < 0) |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
ret = compile_kernel_file(&opencl_ctx); |
|
|
|
|
if (ret < 0) |
|
|
|
|
goto end; |
|
|
|
|
if (opencl_ctx.kernel_code_count <= 0) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"No kernel code is registered, compile kernel file failed\n"); |
|
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
|
goto end; |
|
|
|
|
if (opencl_ctx.kernel_code_count <= 0) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"No kernel code is registered, compile kernel file failed\n"); |
|
|
|
|
ret = AVERROR(EINVAL); |
|
|
|
|
goto end; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
opencl_ctx.init_count++; |
|
|
|
|
|
|
|
|
|
end: |
|
|
|
|
UNLOCK_OPENCL; |
|
|
|
|
return ret; |
|
|
|
@ -617,23 +579,12 @@ end: |
|
|
|
|
void av_opencl_uninit(void) |
|
|
|
|
{ |
|
|
|
|
cl_int status; |
|
|
|
|
int i; |
|
|
|
|
LOCK_OPENCL; |
|
|
|
|
opencl_ctx.init_count--; |
|
|
|
|
if (opencl_ctx.is_user_created) |
|
|
|
|
goto end; |
|
|
|
|
if (opencl_ctx.init_count > 0 || opencl_ctx.kernel_count > 0) |
|
|
|
|
if (opencl_ctx.init_count > 0) |
|
|
|
|
goto end; |
|
|
|
|
for (i = 0; i < opencl_ctx.program_count; i++) { |
|
|
|
|
if (opencl_ctx.programs[i]) { |
|
|
|
|
status = clReleaseProgram(opencl_ctx.programs[i]); |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
|
av_log(&opencl_ctx, AV_LOG_ERROR, |
|
|
|
|
"Could not release OpenCL program: %s\n", av_opencl_errstr(status)); |
|
|
|
|
} |
|
|
|
|
opencl_ctx.programs[i] = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (opencl_ctx.command_queue) { |
|
|
|
|
status = clReleaseCommandQueue(opencl_ctx.command_queue); |
|
|
|
|
if (status != CL_SUCCESS) { |
|
|
|
@ -652,7 +603,7 @@ void av_opencl_uninit(void) |
|
|
|
|
} |
|
|
|
|
free_device_list(&opencl_ctx.device_list); |
|
|
|
|
end: |
|
|
|
|
if ((opencl_ctx.init_count <= 0) && (opencl_ctx.kernel_count <= 0)) |
|
|
|
|
if (opencl_ctx.init_count <= 0) |
|
|
|
|
av_opt_free(&opencl_ctx); //FIXME: free openclutils context
|
|
|
|
|
UNLOCK_OPENCL; |
|
|
|
|
} |
|
|
|
|