[FFmpeg-devel] [PATCH 1/2] libavutil/opencl: add user spec device interface

Stefano Sabatini stefasab at gmail.com
Tue Apr 9 01:58:46 CEST 2013


On date Sunday 2013-04-07 20:10:36 +0800, Wei Gao encoded:
> 

> From d8b8bd67f62d65965684b9a9d8f3b99bbb257233 Mon Sep 17 00:00:00 2001
> From: highgod0401 <highgod0401 at gmail.com>
> Date: Sun, 7 Apr 2013 20:05:31 +0800
> Subject: [PATCH 1/2] add user spec device interface
> 
> ---
>  ffmpeg_opt.c       |  25 ++++
>  libavutil/opencl.c | 379 ++++++++++++++++++++++++++++++-----------------------
>  libavutil/opencl.h |  67 +++++++++-
>  3 files changed, 297 insertions(+), 174 deletions(-)

Missing docs update in doc/ffmpeg.texi.

> 
> diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
> index 63a238d..256319f 100644
> --- a/ffmpeg_opt.c
> +++ b/ffmpeg_opt.c
> @@ -41,6 +41,9 @@
>  #include "libavutil/parseutils.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavutil/pixfmt.h"
> +#if CONFIG_OPENCL
> +#include "libavutil/opencl.h"
> +#endif
>  
>  #define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
>  {\
> @@ -316,6 +319,24 @@ static int opt_attach(void *optctx, const char *opt, const char *arg)
>      o->attachments[o->nb_attachments - 1] = arg;
>      return 0;
>  }

> +#if CONFIG_OPENCL
> +static int opt_opencl(void *optctx, const char *opt, const char *arg)
> +{
> +    char *key, *value;
> +    const char *temp = arg;
> +    int ret = 0;
> +    while (strlen(temp)) {
> +        key = av_get_token(&temp, "=,:[\n");
> +        temp++;
> +        value = av_get_token(&temp, "=,:[\n");
> +        temp++;

buffer overread in case the string is ""

Also why all this special characters? What's the format of the string
you're supposed to parse?

> +        ret = av_opencl_set_option(key, value);
> +        if (ret < 0)
> +            return ret;
> +    }
> +    return ret;
> +}
> +#endif
>  
>  static int opt_map_channel(void *optctx, const char *opt, const char *arg)
>  {
> @@ -2835,5 +2856,9 @@ const OptionDef options[] = {
>      { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(data_disable) },
>          "disable data" },
>  
> +#if CONFIG_OPENCL
> +    { "openclopt",         HAS_ARG,                                     { .func_arg = opt_opencl },

"opencl" or "opencl_options" ?

> +        "set opencl environment options" },
> +#endif
>      { NULL, },
>  };
> diff --git a/libavutil/opencl.c b/libavutil/opencl.c
> index d0f75b9..a8ad0c7 100644
> --- a/libavutil/opencl.c
> +++ b/libavutil/opencl.c
> @@ -24,6 +24,7 @@
>  #include "avstring.h"
>  #include "log.h"
>  #include "avassert.h"
> +#include "opt.h"
>  
>  #if HAVE_PTHREADS
>  
> @@ -43,22 +44,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,16 +67,31 @@ typedef struct {
>       * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
>       */
>      int is_user_created;
> +    AVOpenCLDeviceList device_list;
>  } GPUEnv;
>  
>  typedef struct {
>      const AVClass *class;
>      int log_offset;
>      void *log_ctx;
> +    int init_flag;
> +    int platform_idx;
> +    int device_idx;
> +    char *buildoptions;

nit: build_options

> +    AVDictionary *options;
>  } OpenclUtils;

Note: a possibly cleaner design would be to move this to GPUEnv, and
directly use the global GPUEnv context (which could be renamed to
OpenCLContext).

This would allow to expose this global context and allow the user to
directly set options on it, rather than rely on intermediary av_opt_
wrappers.

Feel free to postpone this to another patch.

>  
> +#define OFFSET(x) offsetof(OpenclUtils, x)
> +

> +static const AVOption opencl_options[]= {
nit+++:                  opencl_options[] = {

> +     { "platform",       "set platform index value",  OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
> +     { "device",         "set device index value",    OFFSET(device_idx),   AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
> +     { "buildoptions",   "build options of opencl",   OFFSET(buildoptions),      AV_OPT_TYPE_STRING, {.str=""}, CHAR_MIN, CHAR_MAX},
> +};
> +
>  static const AVClass openclutils_class = {
>      .class_name                = "OPENCLUTILS",
> +    .option                    = opencl_options,
>      .item_name                 = av_default_item_name,
>      .version                   = LIBAVUTIL_VERSION_INT,
>      .log_level_offset_offset   = offsetof(OpenclUtils, log_offset),
> @@ -170,6 +181,151 @@ static const char *opencl_errstr(cl_int status)
>      return "unknown error";
>  }
>  
> +static int get_device_list(AVOpenCLDeviceList *device_list)
> +{
> +    cl_int status;
> +    int i, j, k, devices_num, temp, ret = 0;
> +    cl_platform_id *platform_ids = NULL;
> +    cl_device_id *device_ids = 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;
> +    }
> +    if (device_list->platform_num > AV_OPENCL_MAX_PLATFORM_NUM) {
> +        av_log(&openclutils, AV_LOG_ERROR,
> +               "Platform number %d is bigger than the max number %d\n",
> +               device_list->platform_num, AV_OPENCL_MAX_PLATFORM_NUM);
> +        return AVERROR(EINVAL);
> +    }
> +    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;
> +    }
> +    for (i = 0; i < device_list->platform_num; i++) {
> +        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);
> +        device_list->platform_node[i].device_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);
> +            if (status == CL_SUCCESS) {
> +                if (devices_num > AV_OPENCL_MAX_DEVICE_NUM) {
> +                    av_log(&openclutils, AV_LOG_ERROR,
> +                            "Device number %d is bigger than the max number %d\n",
> +                            devices_num, AV_OPENCL_MAX_DEVICE_NUM);
> +                    ret = AVERROR(EINVAL);
> +                    goto end;
> +                }
> +                device_ids = av_mallocz(devices_num * 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, device_ids, NULL);
> +                if (status != CL_SUCCESS) {
> +                    av_log(&openclutils, AV_LOG_WARNING,
> +                            "Get device ID error: %s\n", opencl_errstr(status));
> +                    av_freep(&device_ids);
> +                    continue;
> +                }
> +                for (k = 0; k < devices_num; k++) {
> +                    temp = device_list->platform_node[i].device_num;
> +                    device_list->platform_node[i].device_node[temp].device_id = device_ids[k];
> +                    device_list->platform_node[i].device_node[temp].device_type = device_type[j];
> +                    status = clGetDeviceInfo(device_list->platform_node[i].device_node[temp].device_id,
> +                                             CL_DEVICE_NAME,
> +                                             sizeof(device_list->platform_node[i].device_node[temp].device_name),
> +                                             device_list->platform_node[i].device_node[temp].device_name,
> +                                             NULL);
> +                    if (status != CL_SUCCESS) {
> +                        av_log(&openclutils, AV_LOG_WARNING,
> +                                "Get device name error: %s\n", opencl_errstr(status));
> +                        continue;
> +                    }
> +                    device_list->platform_node[i].device_num++;
> +                }
> +                av_freep(&device_ids);
> +            }
> +        }
> +    }
> +end:
> +    av_freep(&platform_ids);
> +    return ret;
> +}
> +

> +AVOpenCLDeviceList *av_opencl_get_device_list(void)
> +{
> +    AVOpenCLDeviceList *device_list = NULL;
> +    LOCK_OPENCL
> +    device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
> +    if (!device_list) {
> +        av_log(&openclutils, AV_LOG_ERROR,
> +               "Could not malloc opencl device list data space\n");
> +        return NULL;
> +    }
> +    if (!gpu_env.device_list.platform_num) {
> +        if (get_device_list(&gpu_env.device_list) < 0) {

> +            av_log(&openclutils, AV_LOG_ERROR,
> +               "Could not get device list from environment\n");

nit: weird indent

> +            av_freep(&device_list);
> +        }
> +    }
> +    *device_list = gpu_env.device_list;

here you're passing global data to the application, which could be
destroyed if the application calls av_opencl_get_device_list() again.

> +    UNLOCK_OPENCL
> +    return device_list;
> +}
> +
> +void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
> +{
> +    av_freep(device_list);
> +}
> +
> +static int parse_options(void)
> +{
> +    int i, ret = 0;
> +    AVDictionaryEntry *opt_entry;
> +    char temp[1024];
> +    if (!openclutils.options)
> +        return 0;
> +    for (i = 0; i < FF_ARRAY_ELEMS(opencl_options); i++) {
> +        opt_entry = av_dict_get(openclutils.options, opencl_options[i].name, NULL, 0);
> +        if (opt_entry) {
> +            snprintf(temp,sizeof(temp), "%s=%s", opt_entry->key, opt_entry->value);
> +            ret = av_set_options_string(&openclutils, temp, "=", ":");

av_opt_set()

> +            if (ret < 0) {
> +                av_log(&openclutils, AV_LOG_ERROR, "Error setting options string: '%s'\n", temp);
> +                return ret;
> +            }
> +        }
> +    }
> +    return ret;
> +}
> +
> +int av_opencl_set_option(const char *key, const char *val)
> +{
> +    int ret = 0;
> +    LOCK_OPENCL
> +    if (!openclutils.init_flag) {
> +        av_opt_set_defaults(&openclutils);
> +        openclutils.init_flag = 1;
> +    }
> +    ret = av_dict_set(&openclutils.options, key, val, 0);
> +    UNLOCK_OPENCL
> +    return ret;
> +}

please merge this with parse_options() (better to avoid unnecessary
wrappers).

> +
>  AVOpenCLExternalEnv *av_opencl_alloc_external_env(void)
>  {
>      AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv));
> @@ -273,13 +429,9 @@ 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;
>  
>      if (ext_opencl_env) {
>          if (gpu_env->is_user_created)
> @@ -288,154 +440,79 @@ 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\n");
> +                    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 = gpu_env->device_list.platform_node[gpu_env->platform_idx].platform_id;
> +            } else {
> +                /* get a usable platform for 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;
>                      }
> -                    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;
> -                        }
> -                    }
> -                    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) {
> +            /* 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 in the user set platform\n");
> -                    ret = AVERROR(EINVAL);
> -                    goto end;
> +                    return AVERROR(EINVAL);
>                  }
> +                gpu_env->device_id = gpu_env->device_list.platform_node[gpu_env->platform_idx].device_node[gpu_env->device_idx].device_id;
> +                gpu_env->device_type = gpu_env->device_list.platform_node[gpu_env->platform_idx].device_node[gpu_env->device_idx].device_type;
> +            } else {
> +                gpu_env->device_id = gpu_env->device_list.platform_node[gpu_env->platform_idx].device_node[0].device_id;
> +                gpu_env->device_type = gpu_env->device_list.platform_node[gpu_env->platform_idx].device_node[0].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 is 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,
> +            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);
>              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 +558,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));
> @@ -504,46 +572,21 @@ end:
>      return ret;
>  }
>  
> -int av_opencl_init(AVDictionary *options, AVOpenCLExternalEnv *ext_opencl_env)
> +int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
>  {
>      int ret = 0;
> -    AVDictionaryEntry *opt_build_entry;
> -    AVDictionaryEntry *opt_platform_entry;
> -    AVDictionaryEntry *opt_device_entry;
> -    char *pos;
>      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, &pos, 10);
> -            if (pos == opt_platform_entry->value) {
> -                av_log(&openclutils, AV_LOG_ERROR, "Platform index should be a number\n");
> -                ret = AVERROR(EINVAL);
> -                goto end;
> -            }
> -        }
> -        if (opt_device_entry) {
> -            gpu_env.usr_spec_dev_info.dev_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);
> -                goto end;
> -            }
> -        }
> +        ret = parse_options();
> +        if (ret < 0)
> +            goto end;
> +        gpu_env.device_idx   = openclutils.device_idx;
> +        gpu_env.platform_idx = openclutils.platform_idx;
>          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);
> +    ret = compile_kernel_file(&gpu_env, openclutils.buildoptions);
>      if (ret < 0)
>          goto end;
>      if (gpu_env.kernel_code_count <= 0) {
> @@ -595,7 +638,9 @@ void av_opencl_uninit(void)
>          }
>          gpu_env.context = NULL;
>      }
> -    av_freep(&(gpu_env.device_ids));
> +    av_dict_free(&openclutils.options);
> +    av_freep(&openclutils.buildoptions);
> +    openclutils.init_flag = 0;
>  end:
>      UNLOCK_OPENCL
>  }
> diff --git a/libavutil/opencl.h b/libavutil/opencl.h
> index 6ebde10..9679129 100644
> --- a/libavutil/opencl.h
> +++ b/libavutil/opencl.h
> @@ -39,6 +39,32 @@
>  
>  #define AV_OPENCL_MAX_KERNEL_NAME_SIZE 150
>  
> +#define AV_OPENCL_MAX_PLATFORM_NUM 200
> +
> +#define AV_OPENCL_MAX_DEVICE_NUM 200
> +
> +#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;

nit here and below:

}_AVOpenCLDeviceNode;

> +
> +typedef struct {
> +    cl_platform_id platform_id;
> +    char platform_name[AV_OPENCL_MAX_PLATFORM_NAME_SIZE];
> +    int device_num;
> +    AVOpenCLDeviceNode device_node[AV_OPENCL_MAX_DEVICE_NUM];
> +}AVOpenCLPlatformNode;
> +
> +typedef struct {
> +    int platform_num;
> +    AVOpenCLPlatformNode platform_node[AV_OPENCL_MAX_PLATFORM_NUM];
> +}AVOpenCLDeviceList;
> +
>  typedef struct {
>      cl_command_queue command_queue;
>      cl_kernel kernel;
> @@ -49,13 +75,45 @@ 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().
> + *
> + * @return pointer to allocated device list
> + */
> +AVOpenCLDeviceList *av_opencl_get_device_list(void);
> +
> +/**
> +  * 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);
> +
> +/**
> +* Currently, the only accepted option are "buildoptions", "platform", "device".
> +*
> +* buildoptions:used to set options to compile registered kernels code. See reference "OpenCL

build_options?

 +*                    Specification Version: 1.2 chapter 5.6.4".
> +*
> +* platform: index of platform in device list
> +*
> +* device: index of device in device list
> +*
> +* @param key                 key of options
> +* @param value              value of options
> +* @return  >=0 on success, a negative error code in case of failure
> +*/
> +int av_opencl_set_option(const char *key, const char *val);
> +
> +/**
>   * Allocate OpenCL external environment.
>   *
>   * It must be freed with av_opencl_free_external_env().
> @@ -87,16 +145,11 @@ 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().
>   *
> - * Currently, the only accepted option is "build_options", used to set
> - * options to compile registered kernels code. See reference "OpenCL
> - * Specification Version: 1.2 chapter 5.6.4".
> - *
> - * @param options        dictionary of key/value options
>   * @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(AVDictionary *options, AVOpenCLExternalEnv *ext_opencl_env);
> + int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env);

I see at least two distinct functional changes in this patch, device
list API addition and option API addition (also the ffmpeg change
could stay in a different patch).

Please split the patch, it is important to keep each patch as small as
possible so that it is easier and faster to review and integrate and
we can easily spot regressions (and analyze code changes) later.
-- 
FFmpeg = Funny and Fierce Mystic Peaceless Enlightened Guru


More information about the ffmpeg-devel mailing list