diff options
author | highgod0401 <highgod0401@gmail.com> | 2013-04-11 08:01:53 +0800 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-04-11 03:48:57 +0200 |
commit | db2de94e95c2095a781892ad7a3d472d952652a8 (patch) | |
tree | 5bcd86271cce21117ceae30cff01b80276abdc67 | |
parent | 3a3d984445f0e49e692f712ebb51a4b7e6bb006c (diff) | |
download | ffmpeg-db2de94e95c2095a781892ad7a3d472d952652a8.tar.gz |
avutil/opencl: add opencl device list APIs 20130411
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavutil/opencl.c | 339 | ||||
-rw-r--r-- | libavutil/opencl.h | 43 |
2 files changed, 240 insertions, 142 deletions
diff --git a/libavutil/opencl.c b/libavutil/opencl.c index d0f75b90ca..a01eab8aa5 100644 --- a/libavutil/opencl.c +++ b/libavutil/opencl.c @@ -43,22 +43,17 @@ static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER; #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; + int platform_idx; + int device_idx; 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; @@ -71,6 +66,7 @@ typedef struct { * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper. */ int is_user_created; + AVOpenCLDeviceList device_list; } GPUEnv; typedef struct { @@ -170,6 +166,151 @@ static const char *opencl_errstr(cl_int status) return "unknown error"; } +static void free_device_list(AVOpenCLDeviceList *device_list) +{ + int i, j; + if (!device_list) + return; + for (i = 0; i < device_list->platform_num; i++) { + if (!device_list->platform_node[i]) + continue; + for (j = 0; j < device_list->platform_node[i]->device_num; j++) { + av_freep(&(device_list->platform_node[i]->device_node[j])); + } + av_freep(&device_list->platform_node[i]->device_node); + av_freep(&device_list->platform_node[i]); + } + av_freep(&device_list->platform_node); + device_list->platform_num = 0; +} + +static int get_device_list(AVOpenCLDeviceList *device_list) +{ + cl_int status; + 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; + AVOpenCLDeviceNode *device_node = NULL; + status = clGetPlatformIDs(0, NULL, &device_list->platform_num); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_ERROR, + "Could not get OpenCL platform ids: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; + } + platform_ids = av_mallocz(device_list->platform_num * sizeof(cl_platform_id)); + if (!platform_ids) + return AVERROR(ENOMEM); + status = clGetPlatformIDs(device_list->platform_num, 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; + } + device_list->platform_node = av_mallocz(device_list->platform_num * sizeof(AVOpenCLPlatformNode *)); + if (!device_list->platform_node) { + ret = AVERROR(ENOMEM); + goto end; + } + devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type)); + if (!devices_num) { + ret = AVERROR(ENOMEM); + goto end; + } + for (i = 0; i < device_list->platform_num; i++) { + device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode)); + if (!device_list->platform_node[i]) { + ret = AVERROR(ENOMEM); + goto end; + } + device_list->platform_node[i]->platform_id = platform_ids[i]; + status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, + sizeof(device_list->platform_node[i]->platform_name), + device_list->platform_node[i]->platform_name, NULL); + total_devices_num = 0; + for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { + status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, + device_type[j], 0, NULL, &devices_num[j]); + total_devices_num += devices_num[j]; + } + device_list->platform_node[i]->device_node = av_mallocz(total_devices_num * sizeof(AVOpenCLDeviceNode *)); + if (!device_list->platform_node[i]->device_node) { + ret = AVERROR(ENOMEM); + goto end; + } + for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { + if (devices_num[j]) { + device_ids = av_mallocz(devices_num[j] * sizeof(cl_device_id)); + if (!device_ids) { + ret = AVERROR(ENOMEM); + goto end; + } + status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j], + devices_num[j], device_ids, NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_WARNING, + "Could not get device ID: %s:\n", opencl_errstr(status)); + av_freep(&device_ids); + continue; + } + for (k = 0; k < devices_num[j]; k++) { + device_num = device_list->platform_node[i]->device_num; + device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode)); + if (!device_list->platform_node[i]->device_node[device_num]) { + ret = AVERROR(ENOMEM); + goto end; + } + device_node = device_list->platform_node[i]->device_node[device_num]; + device_node->device_id = device_ids[k]; + device_node->device_type = device_type[j]; + status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME, + sizeof(device_node->device_name), device_node->device_name, + NULL); + if (status != CL_SUCCESS) { + av_log(&openclutils, AV_LOG_WARNING, + "Could not get device name: %s\n", opencl_errstr(status)); + continue; + } + device_list->platform_node[i]->device_num++; + } + av_freep(&device_ids); + } + } + } +end: + av_freep(&platform_ids); + av_freep(&devices_num); + av_freep(&device_ids); + if (ret < 0) + free_device_list(device_list); + return ret; +} + +int av_opencl_get_device_list(AVOpenCLDeviceList **device_list) +{ + int ret = 0; + *device_list = av_mallocz(sizeof(AVOpenCLDeviceList)); + if (!(*device_list)) { + av_log(&openclutils, AV_LOG_ERROR, "Could not allocate opencl device list\n"); + return AVERROR(ENOMEM); + } + ret = get_device_list(*device_list); + if (ret < 0) { + av_log(&openclutils, AV_LOG_ERROR, "Could not get device list from environment\n"); + free_device_list(*device_list); + av_freep(device_list); + return ret; + } + return ret; +} + +void av_opencl_free_device_list(AVOpenCLDeviceList **device_list) +{ + free_device_list(*device_list); + av_freep(device_list); +} + AVOpenCLExternalEnv *av_opencl_alloc_external_env(void) { AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv)); @@ -273,13 +414,10 @@ end: 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, j, ret = 0; + int i, ret = 0; + AVOpenCLDeviceNode *device_node = NULL; if (ext_opencl_env) { if (gpu_env->is_user_created) @@ -288,154 +426,82 @@ static int init_opencl_env(GPUEnv *gpu_env, AVOpenCLExternalEnv *ext_opencl_env) 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->device_list.platform_num) { + ret = get_device_list(&gpu_env->device_list); + if (ret < 0) { + return ret; + } } - if (gpu_env->usr_spec_dev_info.platform_idx >= 0) { - if (num_platforms < gpu_env->usr_spec_dev_info.platform_idx + 1) { + if (gpu_env->platform_idx >= 0) { + if (gpu_env->device_list.platform_num < gpu_env->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; + if (!gpu_env->device_list.platform_node[gpu_env->platform_idx]->device_num) { + av_log(&openclutils, AV_LOG_ERROR, "No devices in user specific platform with index %d\n", + gpu_env->platform_idx); + return AVERROR(EINVAL); } - 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]; - for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { - status = clGetDeviceIDs(gpu_env->platform_id, device_type[j], 0, NULL, &num_devices); - if (status == CL_SUCCESS) - break; - } - 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; - } - if (i >= num_platforms - 1) { - 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; - } + gpu_env->platform_id = gpu_env->device_list.platform_node[gpu_env->platform_idx]->platform_id; + } else { + /* get a usable platform by default*/ + for (i = 0; i < gpu_env->device_list.platform_num; i++) { + if (gpu_env->device_list.platform_node[i]->device_num) { + gpu_env->platform_id = gpu_env->device_list.platform_node[i]->platform_id; + gpu_env->platform_idx = i; + break; } - i++; } } if (!gpu_env->platform_id) { av_log(&openclutils, AV_LOG_ERROR, "Could not get OpenCL platforms\n"); - ret = AVERROR_EXTERNAL; - goto end; + return AVERROR_EXTERNAL; } - 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; + /* get a usable device*/ + if (gpu_env->device_idx >= 0) { + if (gpu_env->device_list.platform_node[gpu_env->platform_idx]->device_num < gpu_env->device_idx + 1) { + av_log(&openclutils, AV_LOG_ERROR, + "Could not get OpenCL device idx %d in the user set platform\n", gpu_env->platform_idx); + return AVERROR(EINVAL); } + } else { + gpu_env->device_idx = 0; } + device_node = gpu_env->device_list.platform_node[gpu_env->platform_idx]->device_node[gpu_env->device_idx]; + gpu_env->device_id = device_node->device_id; + gpu_env->device_type = device_node->device_type; + /* * Use available platform. */ - av_log(&openclutils, AV_LOG_VERBOSE, "Platform Name: %s\n", platform_name); + av_log(&openclutils, AV_LOG_VERBOSE, "Platform Name: %s, device id: 0x%x\n", + gpu_env->device_list.platform_node[gpu_env->platform_idx]->platform_name, + (unsigned int)gpu_env->device_id); cps[0] = CL_CONTEXT_PLATFORM; cps[1] = (cl_context_properties)gpu_env->platform_id; cps[2] = 0; - /* Check for GPU. */ - for (i = 0; i < FF_ARRAY_ELEMS(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) - break; - } - if (!gpu_env->context) { - av_log(&openclutils, AV_LOG_ERROR, - "Could not get OpenCL context from device type: %s\n", opencl_errstr(status)); - 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); + 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 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; + "Could not get OpenCL context from device type: %s\n", opencl_errstr(status)); + return AVERROR_EXTERNAL; } - gpu_env->command_queue = clCreateCommandQueue(gpu_env->context, gpu_env->device_ids[i], + gpu_env->command_queue = clCreateCommandQueue(gpu_env->context, gpu_env->device_id, 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; + return AVERROR_EXTERNAL; } } } -end: - av_free(platform_ids); return ret; } @@ -481,17 +547,8 @@ static int compile_kernel_file(GPUEnv *gpu_env, const char *build_options) 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); - + 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)); @@ -516,10 +573,10 @@ int av_opencl_init(AVDictionary *options, AVOpenCLExternalEnv *ext_opencl_env) 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; + gpu_env.platform_idx = -1; + gpu_env.device_idx = -1; if (opt_platform_entry) { - gpu_env.usr_spec_dev_info.platform_idx = strtol(opt_platform_entry->value, &pos, 10); + gpu_env.platform_idx = strtol(opt_platform_entry->value, &pos, 10); if (pos == opt_platform_entry->value) { av_log(&openclutils, AV_LOG_ERROR, "Platform index should be a number\n"); ret = AVERROR(EINVAL); @@ -527,7 +584,7 @@ int av_opencl_init(AVDictionary *options, AVOpenCLExternalEnv *ext_opencl_env) } } if (opt_device_entry) { - gpu_env.usr_spec_dev_info.dev_idx = strtol(opt_device_entry->value, &pos, 10); + gpu_env.device_idx = strtol(opt_device_entry->value, &pos, 10); if (pos == opt_platform_entry->value) { av_log(&openclutils, AV_LOG_ERROR, "Device index should be a number\n"); ret = AVERROR(EINVAL); @@ -595,7 +652,7 @@ void av_opencl_uninit(void) } gpu_env.context = NULL; } - av_freep(&(gpu_env.device_ids)); + free_device_list(&gpu_env.device_list); end: UNLOCK_OPENCL } diff --git a/libavutil/opencl.h b/libavutil/opencl.h index 6ebde1023b..bcb25ed8be 100644 --- a/libavutil/opencl.h +++ b/libavutil/opencl.h @@ -39,6 +39,28 @@ #define AV_OPENCL_MAX_KERNEL_NAME_SIZE 150 +#define AV_OPENCL_MAX_DEVICE_NAME_SIZE 100 + +#define AV_OPENCL_MAX_PLATFORM_NAME_SIZE 100 + +typedef struct { + int device_type; + char device_name[AV_OPENCL_MAX_DEVICE_NAME_SIZE]; + cl_device_id device_id; +} AVOpenCLDeviceNode; + +typedef struct { + cl_platform_id platform_id; + char platform_name[AV_OPENCL_MAX_PLATFORM_NAME_SIZE]; + int device_num; + AVOpenCLDeviceNode **device_node; +} AVOpenCLPlatformNode; + +typedef struct { + int platform_num; + AVOpenCLPlatformNode **platform_node; +} AVOpenCLDeviceList; + typedef struct { cl_command_queue command_queue; cl_kernel kernel; @@ -49,13 +71,32 @@ typedef struct { 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; char *platform_name; } AVOpenCLExternalEnv; /** + * Get OpenCL device list. + * + * It must be freed with av_opencl_free_device_list(). + * + * @param device_list pointer to OpenCL environment device list, + * should be released by av_opencl_free_device_list() + * + * @return >=0 on success, a negative error code in case of failure + */ +int av_opencl_get_device_list(AVOpenCLDeviceList **device_list); + +/** + * Free OpenCL device list. + * + * @param device_list pointer to OpenCL environment device list + * created by av_opencl_get_device_list() + */ +void av_opencl_free_device_list(AVOpenCLDeviceList **device_list); + +/** * Allocate OpenCL external environment. * * It must be freed with av_opencl_free_external_env(). |