diff options
author | highgod0401 <highgod0401@gmail.com> | 2013-04-01 17:46:11 +0800 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-04-01 12:52:13 +0200 |
commit | 189cbc1a0357eff9ebda70d74f886f58d3d7d574 (patch) | |
tree | 6f02c1dc3bea31ba5a87311b2b8d2c274d7bd144 /libavutil/opencl.c | |
parent | 24f822c3ab99c33f59a5b181682e3fb507bfe35d (diff) | |
download | ffmpeg-189cbc1a0357eff9ebda70d74f886f58d3d7d574.tar.gz |
opencl wrapper based on comments on 20130401
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavutil/opencl.c')
-rw-r--r-- | libavutil/opencl.c | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/libavutil/opencl.c b/libavutil/opencl.c new file mode 100644 index 0000000000..dc3b859543 --- /dev/null +++ b/libavutil/opencl.c @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com> + * Copyright (C) 2012 Li Cao <li@multicorewareinc.com> + * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opencl.h" +#include "avstring.h" +#include "log.h" +#include "avassert.h" + +#if HAVE_PTHREADS + +#include <pthread.h> +static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER; + +#define LOCK_OPENCL pthread_mutex_lock(&atomic_opencl_lock); +#define UNLOCK_OPENCL pthread_mutex_unlock(&atomic_opencl_lock); + +#elif !HAVE_THREADS +#define LOCK_OPENCL +#define UNLOCK_OPENCL +#endif + + +#define MAX_KERNEL_NUM 500 +#define MAX_KERNEL_CODE_NUM 200 + +typedef struct { + int dev_idx; + int platform_idx; +} UserSpecDevInfo; + +typedef struct { + int is_compiled; + const char *kernel_string; +} KernelCode; + +typedef struct { + int init_count; + UserSpecDevInfo usr_spec_dev_info; + cl_platform_id platform_id; + cl_device_type device_type; + cl_context context; + cl_device_id *device_ids; + cl_device_id device_id; + cl_command_queue command_queue; + int program_count; + cl_program programs[MAX_KERNEL_CODE_NUM]; + int kernel_code_count; + KernelCode kernel_code[MAX_KERNEL_CODE_NUM]; + int kernel_count; + /** + * if set to 1, the OpenCL environment was created by the user and + * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper. + */ + int is_user_created; +} GPUEnv; + +typedef struct { + const AVClass *class; + int log_offset; + void *log_ctx; +} OpenclUtils; + +static const AVClass openclutils_class = {"OPENCLUTILS", av_default_item_name, + NULL, LIBAVUTIL_VERSION_INT, + offsetof(OpenclUtils, log_offset), + offsetof(OpenclUtils, log_ctx)}; +static OpenclUtils openclutils = {&openclutils_class}; +static GPUEnv gpu_env; + +typedef struct { + int err_code; + const char *err_str; +} OpenclErrorMsg; + +static const OpenclErrorMsg opencl_err_msg[] = { + {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"}, + {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"}, + {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"}, + {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"}, + {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"}, + {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"}, + {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"}, + {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"}, + {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"}, + {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"}, + {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"}, + {CL_MAP_FAILURE, "MAP FAILURE"}, + {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"}, + {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"}, + {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"}, + {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"}, + {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"}, + {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"}, + {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"}, + {CL_INVALID_VALUE, "INVALID VALUE"}, + {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"}, + {CL_INVALID_PLATFORM, "INVALID PLATFORM"}, + {CL_INVALID_DEVICE, "INVALID DEVICE"}, + {CL_INVALID_CONTEXT, "INVALID CONTEXT"}, + {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"}, + {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"}, + {CL_INVALID_HOST_PTR, "INVALID HOST PTR"}, + {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"}, + {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"}, + {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"}, + {CL_INVALID_SAMPLER, "INVALID SAMPLER"}, + {CL_INVALID_BINARY, "INVALID BINARY"}, + {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"}, + {CL_INVALID_PROGRAM, "INVALID PROGRAM"}, + {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"}, + {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"}, + {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"}, + {CL_INVALID_KERNEL, "INVALID KERNEL"}, + {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"}, + {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"}, + {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"}, + {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"}, + {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"}, + {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"}, + {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"}, + {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"}, + {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"}, + {CL_INVALID_EVENT, "INVALID EVENT"}, + {CL_INVALID_OPERATION, "INVALID OPERATION"}, + {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"}, + {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"}, + {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"}, + {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"}, + {CL_INVALID_PROPERTY, "INVALID PROPERTY"}, + {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"}, + {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"}, + {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"}, + {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"}, +}; + +static const char *opencl_errstr(cl_int status) +{ + int i; + for (i = 0; i < sizeof(opencl_err_msg); i++) { + if (opencl_err_msg[i].err_code == status) + return opencl_err_msg[i].err_str; + } + return "unknown error"; +} + +AVOpenCLExternalEnv *av_opencl_alloc_external_env(void) +{ + AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv)); + if (!ext) { + av_log(&openclutils, AV_LOG_ERROR, + "Could not malloc external opencl environment data space\n"); + } + return ext; +} + +void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env) +{ + av_freep(ext_opencl_env); +} + +int av_opencl_register_kernel_code(const char *kernel_code) +{ + int i, ret = 0; + LOCK_OPENCL; + if (gpu_env.kernel_code_count >= MAX_KERNEL_CODE_NUM) { + av_log(&openclutils, AV_LOG_ERROR, + "Could not register kernel code, maximum number of registered kernel code %d already reached\n", + MAX_KERNEL_CODE_NUM); + ret = AVERROR(EINVAL); + goto end; + } + for (i = 0; i < gpu_env.kernel_code_count; i++) { + if (gpu_env.kernel_code[i].kernel_string == kernel_code) { + av_log(&openclutils, AV_LOG_WARNING, "Same kernel code has been registered\n"); + goto end; + } + } + gpu_env.kernel_code[gpu_env.kernel_code_count].kernel_string = kernel_code; + gpu_env.kernel_code[gpu_env.kernel_code_count].is_compiled = 0; + gpu_env.kernel_code_count++; +end: + UNLOCK_OPENCL; + return ret; +} + +int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name) +{ + cl_int status; + int i, ret = 0; + LOCK_OPENCL; + if (strlen(kernel_name) + 1 > AV_OPENCL_MAX_KERNEL_NAME_SIZE) { + av_log(&openclutils, AV_LOG_ERROR, "Created kernel name %s is too long\n", kernel_name); + ret = AVERROR(EINVAL); + goto end; + } + if (!env->kernel) { + if (gpu_env.kernel_count >= MAX_KERNEL_NUM) { + av_log(&openclutils, 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; + } + for (i = 0; i < gpu_env.program_count; i++) { + env->kernel = clCreateKernel(gpu_env.programs[i], kernel_name, &status); + if (status == CL_SUCCESS) + break; + } + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not create OpenCL kernel: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + gpu_env.kernel_count++; + env->command_queue = gpu_env.command_queue; + av_strlcpy(env->kernel_name, kernel_name, sizeof(env->kernel_name)); + } +end: + UNLOCK_OPENCL; + return ret; +} + +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(&openclutils, AV_LOG_ERROR, "Could not release kernel: %s\n", + opencl_errstr(status)); + } + env->kernel = NULL; + env->command_queue = NULL; + env->kernel_name[0] = 0; + gpu_env.kernel_count--; +end: + UNLOCK_OPENCL +} + +static int init_opencl_env(GPUEnv *gpu_env, AVOpenCLExternalEnv *ext_opencl_env) +{ + size_t device_length; + cl_int status; + cl_uint num_platforms, num_devices; + cl_platform_id *platform_ids = NULL; + cl_context_properties cps[3]; + char platform_name[100]; + int i, ret = 0; + cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT}; + if (ext_opencl_env) { + if (gpu_env->is_user_created) + return 0; + gpu_env->platform_id = ext_opencl_env->platform_id; + gpu_env->is_user_created = 1; + gpu_env->command_queue = ext_opencl_env->command_queue; + gpu_env->context = ext_opencl_env->context; + gpu_env->device_ids = ext_opencl_env->device_ids; + gpu_env->device_id = ext_opencl_env->device_id; + gpu_env->device_type = ext_opencl_env->device_type; + } else { + if (!gpu_env->is_user_created) { + status = clGetPlatformIDs(0, NULL, &num_platforms); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL platform ids: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + if (gpu_env->usr_spec_dev_info.platform_idx >= 0) { + if (num_platforms < gpu_env->usr_spec_dev_info.platform_idx + 1) { + av_log(&openclutils, AV_LOG_ERROR, "User set platform index not exist\n"); + return AVERROR(EINVAL); + } + } + if (num_platforms > 0) { + platform_ids = av_mallocz(num_platforms * sizeof(cl_platform_id)); + if (!platform_ids) { + ret = AVERROR(ENOMEM); + goto end; + } + status = clGetPlatformIDs(num_platforms, platform_ids, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL platform ids: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + i = 0; + if (gpu_env->usr_spec_dev_info.platform_idx >= 0) { + i = gpu_env->usr_spec_dev_info.platform_idx; + } + while (i < num_platforms) { + status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, + sizeof(platform_name), platform_name, + NULL); + + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL platform info: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + gpu_env->platform_id = platform_ids[i]; + status = clGetDeviceIDs(gpu_env->platform_id, CL_DEVICE_TYPE_GPU, + 0, NULL, &num_devices); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL device number:%s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + if (num_devices == 0) { + //find CPU device + status = clGetDeviceIDs(gpu_env->platform_id, CL_DEVICE_TYPE_CPU, + 0, NULL, &num_devices); + } + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL device ids: %s\n", opencl_errstr(status)); + ret = AVERROR(EINVAL);; + goto end; + } + if (num_devices) + break; + if (gpu_env->usr_spec_dev_info.platform_idx >= 0) { + av_log(&openclutils, AV_LOG_ERROR, "Device number of user set platform is 0\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + i++; + + } + } + if (!gpu_env->platform_id) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL platforms\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + if (gpu_env->usr_spec_dev_info.dev_idx >= 0) { + if (num_devices < gpu_env->usr_spec_dev_info.dev_idx + 1) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL device idx in the user set platform\n"); + ret = AVERROR(EINVAL);; + goto end; + } + } + + /* + * Use available platform. + */ + + av_log(&openclutils, AV_LOG_VERBOSE, "Platform Name: %s\n", platform_name); + cps[0] = CL_CONTEXT_PLATFORM; + cps[1] = (cl_context_properties)gpu_env->platform_id; + cps[2] = 0; + /* Check for GPU. */ + + for (i = 0; i < sizeof(device_type); i++) { + gpu_env->device_type = device_type[i]; + gpu_env->context = clCreateContextFromType(cps, gpu_env->device_type, + NULL, NULL, &status); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL context from device type: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + if (gpu_env->context) + break; + } + if (!gpu_env->context) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL context from device type\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + /* Detect OpenCL devices. */ + /* First, get the size of device list data */ + status = clGetContextInfo(gpu_env->context, CL_CONTEXT_DEVICES, + 0, NULL, &device_length); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL device length: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + if (device_length == 0) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL device length\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + /* Now allocate memory for device list based on the size we got earlier */ + gpu_env->device_ids = av_mallocz(device_length); + if (!gpu_env->device_ids) { + ret = AVERROR(ENOMEM); + goto end; + } + /* Now, get the device list data */ + status = clGetContextInfo(gpu_env->context, CL_CONTEXT_DEVICES, device_length, + gpu_env->device_ids, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL context info: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + /* Create OpenCL command queue. */ + i = 0; + if (gpu_env->usr_spec_dev_info.dev_idx >= 0) { + i = gpu_env->usr_spec_dev_info.dev_idx; + } + gpu_env->command_queue = clCreateCommandQueue(gpu_env->context, gpu_env->device_ids[i], + 0, &status); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not create OpenCL command queue: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + } + } +end: + av_free(platform_ids); + return ret; +} + +static int compile_kernel_file(GPUEnv *gpu_env, const char *build_options) +{ + cl_int status; + char *temp, *source_str = NULL; + size_t source_str_len = 0; + int i, ret = 0; + + for (i = 0; i < gpu_env->kernel_code_count; i++) { + if (!gpu_env->kernel_code[i].is_compiled) + source_str_len += strlen(gpu_env->kernel_code[i].kernel_string); + } + if (!source_str_len) { + return 0; + } + source_str = av_mallocz(source_str_len + 1); + if (!source_str) { + return AVERROR(ENOMEM); + } + temp = source_str; + for (i = 0; i < gpu_env->kernel_code_count; i++) { + if (!gpu_env->kernel_code[i].is_compiled) { + memcpy(temp, gpu_env->kernel_code[i].kernel_string, + strlen(gpu_env->kernel_code[i].kernel_string)); + gpu_env->kernel_code[i].is_compiled = 1; + temp += strlen(gpu_env->kernel_code[i].kernel_string); + } + } + /* create a CL program using the kernel source */ + gpu_env->programs[gpu_env->program_count] = clCreateProgramWithSource(gpu_env->context, + 1, (const char **)(&source_str), + &source_str_len, &status); + if(status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not create OpenCL program with source code: %s\n", + opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + if (!gpu_env->programs[gpu_env->program_count]) { + av_log(&openclutils, AV_LOG_ERROR, "Created program is NULL\n"); + ret = AVERROR_EXTERNAL; + goto end; + } + i = 0; + if (gpu_env->usr_spec_dev_info.dev_idx >= 0) + i = gpu_env->usr_spec_dev_info.dev_idx; + /* create a cl program executable for all the devices specified */ + if (!gpu_env->is_user_created) + status = clBuildProgram(gpu_env->programs[gpu_env->program_count], 1, &gpu_env->device_ids[i], + build_options, NULL, NULL); + else + status = clBuildProgram(gpu_env->programs[gpu_env->program_count], 1, &(gpu_env->device_id), + build_options, NULL, NULL); + + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not compile OpenCL kernel: %s\n", opencl_errstr(status)); + ret = AVERROR_EXTERNAL; + goto end; + } + gpu_env->program_count++; +end: + av_free(source_str); + return ret; +} + +int av_opencl_init(AVDictionary *options, AVOpenCLExternalEnv *ext_opencl_env) +{ + int ret = 0; + AVDictionaryEntry *opt_build_entry; + AVDictionaryEntry *opt_platform_entry; + AVDictionaryEntry *opt_device_entry; + LOCK_OPENCL + if (!gpu_env.init_count) { + opt_platform_entry = av_dict_get(options, "platform_idx", NULL, 0); + opt_device_entry = av_dict_get(options, "device_idx", NULL, 0); + /*initialize devices, context, command_queue*/ + gpu_env.usr_spec_dev_info.platform_idx = -1; + gpu_env.usr_spec_dev_info.dev_idx = -1; + if (opt_platform_entry) { + gpu_env.usr_spec_dev_info.platform_idx = strtol(opt_platform_entry->value, NULL, 10); + } + if (opt_device_entry) { + gpu_env.usr_spec_dev_info.dev_idx = strtol(opt_device_entry->value, NULL, 10); + } + ret = init_opencl_env(&gpu_env, ext_opencl_env); + if (ret < 0) + goto end; + } + /*initialize program, kernel_name, kernel_count*/ + opt_build_entry = av_dict_get(options, "build_options", NULL, 0); + if (opt_build_entry) + ret = compile_kernel_file(&gpu_env, opt_build_entry->value); + else + ret = compile_kernel_file(&gpu_env, NULL); + if (ret < 0) + goto end; + av_assert1(gpu_env.kernel_code_count > 0); + gpu_env.init_count++; + +end: + UNLOCK_OPENCL + return ret; +} + +void av_opencl_uninit(void) +{ + cl_int status; + int i; + LOCK_OPENCL + gpu_env.init_count--; + if (gpu_env.is_user_created) + goto end; + if ((gpu_env.init_count > 0) || (gpu_env.kernel_count > 0)) + goto end; + for (i = 0; i < gpu_env.program_count; i++) { + if (gpu_env.programs[i]) { + status = clReleaseProgram(gpu_env.programs[i]); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not release OpenCL program: %s\n", opencl_errstr(status)); + } + gpu_env.programs[i] = NULL; + } + } + if (gpu_env.command_queue) { + status = clReleaseCommandQueue(gpu_env.command_queue); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not release OpenCL command queue: %s\n", opencl_errstr(status)); + } + gpu_env.command_queue = NULL; + } + if (gpu_env.context) { + status = clReleaseContext(gpu_env.context); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not release OpenCL context: %s\n", opencl_errstr(status)); + } + gpu_env.context = NULL; + } + av_freep(&(gpu_env.device_ids)); +end: + UNLOCK_OPENCL +} + +int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr) +{ + cl_int status; + *cl_buf = clCreateBuffer(gpu_env.context, flags, cl_buf_size, host_ptr, &status); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + return 0; +} + +void av_opencl_buffer_release(cl_mem *cl_buf) +{ + cl_int status = 0; + if (!cl_buf) + return; + status = clReleaseMemObject(*cl_buf); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not release OpenCL buffer: %s\n", opencl_errstr(status)); + } + memset(cl_buf, 0, sizeof(*cl_buf)); +} + +int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size) +{ + cl_int status; + void *mapped = clEnqueueMapBuffer(gpu_env.command_queue, dst_cl_buf, + CL_TRUE,CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size, + 0, NULL, NULL, &status); + + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not map OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + memcpy(mapped, src_buf, buf_size); + + status = clEnqueueUnmapMemObject(gpu_env.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + return 0; +} + +int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size) +{ + cl_int status; + void *mapped = clEnqueueMapBuffer(gpu_env.command_queue, src_cl_buf, + CL_TRUE,CL_MAP_READ, 0, buf_size, + 0, NULL, NULL, &status); + + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not map OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + memcpy(dst_buf, mapped, buf_size); + + status = clEnqueueUnmapMemObject(gpu_env.command_queue, src_cl_buf, mapped, 0, NULL, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + return 0; +} + +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) +{ + int i, buffer_size = 0; + uint8_t *temp; + cl_int status; + void *mapped; + if ((unsigned int)plane_num > 8) { + return AVERROR(EINVAL); + } + for (i = 0;i < plane_num;i++) { + buffer_size += plane_size[i]; + } + if (buffer_size > cl_buffer_size) { + av_log(&openclutils, AV_LOG_ERROR, "Cannot write image to OpenCL buffer: buffer too small\n"); + return AVERROR(EINVAL); + } + mapped = clEnqueueMapBuffer(gpu_env.command_queue, dst_cl_buf, + CL_TRUE,CL_MAP_WRITE, 0, buffer_size + dst_cl_offset, + 0, NULL, NULL, &status); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not map OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + temp = mapped; + temp += dst_cl_offset; + for (i = 0; i < plane_num; i++) { + memcpy(temp, src_data[i], plane_size[i]); + temp += plane_size[i]; + } + status = clEnqueueUnmapMemObject(gpu_env.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + return 0; +} + +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) +{ + int i,buffer_size = 0,ret = 0; + uint8_t *temp; + void *mapped; + cl_int status; + if ((unsigned int)plane_num > 8) { + return AVERROR(EINVAL); + } + for (i = 0;i < plane_num;i++) { + buffer_size += plane_size[i]; + } + if (buffer_size > cl_buffer_size) { + av_log(&openclutils, AV_LOG_ERROR, "Cannot write image to CPU buffer: OpenCL buffer too small\n"); + return AVERROR(EINVAL); + } + mapped = clEnqueueMapBuffer(gpu_env.command_queue, src_cl_buf, + CL_TRUE,CL_MAP_READ, 0, buffer_size, + 0, NULL, NULL, &status); + + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not map OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + temp = mapped; + if (ret >= 0) { + for (i = 0;i < plane_num;i++) { + memcpy(dst_data[i], temp, plane_size[i]); + temp += plane_size[i]; + } + } + status = clEnqueueUnmapMemObject(gpu_env.command_queue, src_cl_buf, mapped, 0, NULL, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + return 0; +} |