From 668255479085728bdf875a1b01c76201e2562a47 Mon Sep 17 00:00:00 2001 From: Lenny Wang Date: Sun, 3 Nov 2013 21:58:09 -0600 Subject: avutil/opencl: compile kernels separately Reviewed-by: Wei Gao Signed-off-by: Michael Niedermayer --- libavutil/opencl.c | 193 ++++++++++++++++++++-------------------------------- libavutil/opencl.h | 40 +++++++++-- libavutil/version.h | 5 +- 3 files changed, 109 insertions(+), 129 deletions(-) diff --git a/libavutil/opencl.c b/libavutil/opencl.c index e0b28c309c..ae4c476396 100644 --- a/libavutil/opencl.c +++ b/libavutil/opencl.c @@ -1,7 +1,8 @@ /* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao + * Copyright (C) 2012 Peng Gao + * Copyright (C) 2012 Li Cao + * Copyright (C) 2012 Wei Gao + * Copyright (C) 2013 Lenny Wang * * 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; } diff --git a/libavutil/opencl.h b/libavutil/opencl.h index 094c108a3c..e4ecbf812c 100644 --- a/libavutil/opencl.h +++ b/libavutil/opencl.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao + * Copyright (C) 2012 Peng Gao + * Copyright (C) 2012 Li Cao + * Copyright (C) 2012 Wei Gao + * Copyright (C) 2013 Lenny Wang * * This file is part of FFmpeg. * @@ -39,6 +40,8 @@ #endif #include "dict.h" +#include "libavutil/version.h" + #define AV_OPENCL_KERNEL( ... )# __VA_ARGS__ #define AV_OPENCL_MAX_KERNEL_NAME_SIZE 150 @@ -65,11 +68,13 @@ typedef struct { AVOpenCLPlatformNode **platform_node; } AVOpenCLDeviceList; +#if FF_API_OLD_OPENCL typedef struct { cl_command_queue command_queue; cl_kernel kernel; char kernel_name[AV_OPENCL_MAX_KERNEL_NAME_SIZE]; } AVOpenCLKernelEnv; +#endif typedef struct { cl_platform_id platform_id; @@ -107,7 +112,6 @@ void av_opencl_free_device_list(AVOpenCLDeviceList **device_list); * av_opencl_init() operation. * * The currently accepted options are: - * - build_options: set options to compile registered kernels code * - platform: set index of platform in device list * - device: set index of device in device list * @@ -174,15 +178,15 @@ const char *av_opencl_errstr(cl_int status); int av_opencl_register_kernel_code(const char *kernel_code); /** - * Initialize the run time OpenCL environment and compile the kernel - * code registered with av_opencl_register_kernel_code(). + * Initialize the run time OpenCL environment * * @param ext_opencl_env external OpenCL environment, created by an * application program, ignored if set to NULL * @return >=0 on success, a negative error code in case of failure */ - int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env); +int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env); +#if FF_API_OLD_OPENCL /** * Create kernel object in the specified kernel environment. * @@ -190,8 +194,27 @@ int av_opencl_register_kernel_code(const char *kernel_code); * the environment used to run the kernel * @param kernel_name kernel function name * @return >=0 on success, a negative error code in case of failure + * @deprecated, use clCreateKernel */ int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name); +#endif + +/** + * compile specific OpenCL kernel source + * + * @param program_name pointer to a program name used for identification + * @param build_opts pointer to a string that describes the preprocessor + * build options to be used for building the program + * @return a cl_program object + */ +cl_program av_opencl_compile(const char *program_name, const char* build_opts); + +/** + * get OpenCL command queue + * + * @return a cl_command_queue object + */ +cl_command_queue av_opencl_get_command_queue(void); /** * Create OpenCL buffer. @@ -268,13 +291,16 @@ int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_n */ void av_opencl_buffer_release(cl_mem *cl_buf); +#if FF_API_OLD_OPENCL /** * Release kernel object. * * @param env kernel environment where the kernel object was created * with av_opencl_create_kernel() + * @deprecated, use clReleaseKernel */ void av_opencl_release_kernel(AVOpenCLKernelEnv *env); +#endif /** * Release OpenCL environment. diff --git a/libavutil/version.h b/libavutil/version.h index 2f91fc0a73..2e2f5710ba 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -75,7 +75,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 52 -#define LIBAVUTIL_VERSION_MINOR 51 +#define LIBAVUTIL_VERSION_MINOR 52 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -141,6 +141,9 @@ #ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT #define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 53) #endif +#ifndef FF_API_OLD_OPENCL +#define FF_API_OLD_OPENCL (LIBAVUTIL_VERSION_MAJOR < 53) +#endif /** * @} -- cgit v1.2.3