avutil/opencl: compile kernels separately
authorLenny Wang <lenny@multicorewareinc.com>
Mon, 4 Nov 2013 03:58:09 +0000 (21:58 -0600)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 5 Nov 2013 13:29:55 +0000 (14:29 +0100)
Reviewed-by: Wei Gao <highgod0401@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavutil/opencl.c
libavutil/opencl.h
libavutil/version.h

index e0b28c3..ae4c476 100644 (file)
@@ -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;
 }
index 094c108..e4ecbf8 100644 (file)
@@ -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,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.
index 2f91fc0..2e2f571 100644 (file)
@@ -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, \
 #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
 
 /**
  * @}