annotate ffmpeg/libavutil/opencl.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
yading@11 3 * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
yading@11 4 * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com>
yading@11 5 *
yading@11 6 * This file is part of FFmpeg.
yading@11 7 *
yading@11 8 * FFmpeg is free software; you can redistribute it and/or
yading@11 9 * modify it under the terms of the GNU Lesser General Public
yading@11 10 * License as published by the Free Software Foundation; either
yading@11 11 * version 2.1 of the License, or (at your option) any later version.
yading@11 12 *
yading@11 13 * FFmpeg is distributed in the hope that it will be useful,
yading@11 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 16 * Lesser General Public License for more details.
yading@11 17 *
yading@11 18 * You should have received a copy of the GNU Lesser General Public
yading@11 19 * License along with FFmpeg; if not, write to the Free Software
yading@11 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 21 */
yading@11 22
yading@11 23 #include "opencl.h"
yading@11 24 #include "avstring.h"
yading@11 25 #include "log.h"
yading@11 26 #include "avassert.h"
yading@11 27 #include "opt.h"
yading@11 28
yading@11 29 #if HAVE_PTHREADS
yading@11 30
yading@11 31 #include <pthread.h>
yading@11 32 static pthread_mutex_t atomic_opencl_lock = PTHREAD_MUTEX_INITIALIZER;
yading@11 33
yading@11 34 #define LOCK_OPENCL pthread_mutex_lock(&atomic_opencl_lock);
yading@11 35 #define UNLOCK_OPENCL pthread_mutex_unlock(&atomic_opencl_lock);
yading@11 36
yading@11 37 #elif !HAVE_THREADS
yading@11 38 #define LOCK_OPENCL
yading@11 39 #define UNLOCK_OPENCL
yading@11 40 #endif
yading@11 41
yading@11 42
yading@11 43 #define MAX_KERNEL_NUM 500
yading@11 44 #define MAX_KERNEL_CODE_NUM 200
yading@11 45
yading@11 46 typedef struct {
yading@11 47 int is_compiled;
yading@11 48 const char *kernel_string;
yading@11 49 } KernelCode;
yading@11 50
yading@11 51 typedef struct {
yading@11 52 const AVClass *class;
yading@11 53 int log_offset;
yading@11 54 void *log_ctx;
yading@11 55 int init_count;
yading@11 56 int opt_init_flag;
yading@11 57 /**
yading@11 58 * if set to 1, the OpenCL environment was created by the user and
yading@11 59 * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
yading@11 60 */
yading@11 61 int is_user_created;
yading@11 62 int platform_idx;
yading@11 63 int device_idx;
yading@11 64 char *build_options;
yading@11 65 cl_platform_id platform_id;
yading@11 66 cl_device_type device_type;
yading@11 67 cl_context context;
yading@11 68 cl_device_id device_id;
yading@11 69 cl_command_queue command_queue;
yading@11 70 int program_count;
yading@11 71 cl_program programs[MAX_KERNEL_CODE_NUM];
yading@11 72 int kernel_code_count;
yading@11 73 KernelCode kernel_code[MAX_KERNEL_CODE_NUM];
yading@11 74 int kernel_count;
yading@11 75 AVOpenCLDeviceList device_list;
yading@11 76 } OpenclContext;
yading@11 77
yading@11 78 #define OFFSET(x) offsetof(OpenclContext, x)
yading@11 79
yading@11 80 static const AVOption opencl_options[] = {
yading@11 81 { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
yading@11 82 { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
yading@11 83 { "build_options", "build options of opencl", OFFSET(build_options), AV_OPT_TYPE_STRING, {.str="-I."}, CHAR_MIN, CHAR_MAX},
yading@11 84 };
yading@11 85
yading@11 86 static const AVClass openclutils_class = {
yading@11 87 .class_name = "OPENCLUTILS",
yading@11 88 .option = opencl_options,
yading@11 89 .item_name = av_default_item_name,
yading@11 90 .version = LIBAVUTIL_VERSION_INT,
yading@11 91 .log_level_offset_offset = offsetof(OpenclContext, log_offset),
yading@11 92 .parent_log_context_offset = offsetof(OpenclContext, log_ctx),
yading@11 93 };
yading@11 94
yading@11 95 static OpenclContext opencl_ctx = {&openclutils_class};
yading@11 96
yading@11 97 static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT};
yading@11 98
yading@11 99 typedef struct {
yading@11 100 int err_code;
yading@11 101 const char *err_str;
yading@11 102 } OpenclErrorMsg;
yading@11 103
yading@11 104 static const OpenclErrorMsg opencl_err_msg[] = {
yading@11 105 {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"},
yading@11 106 {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"},
yading@11 107 {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"},
yading@11 108 {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"},
yading@11 109 {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"},
yading@11 110 {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"},
yading@11 111 {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"},
yading@11 112 {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"},
yading@11 113 {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"},
yading@11 114 {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"},
yading@11 115 {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"},
yading@11 116 {CL_MAP_FAILURE, "MAP FAILURE"},
yading@11 117 {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"},
yading@11 118 {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
yading@11 119 {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"},
yading@11 120 {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"},
yading@11 121 {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"},
yading@11 122 {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"},
yading@11 123 {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"},
yading@11 124 {CL_INVALID_VALUE, "INVALID VALUE"},
yading@11 125 {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"},
yading@11 126 {CL_INVALID_PLATFORM, "INVALID PLATFORM"},
yading@11 127 {CL_INVALID_DEVICE, "INVALID DEVICE"},
yading@11 128 {CL_INVALID_CONTEXT, "INVALID CONTEXT"},
yading@11 129 {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"},
yading@11 130 {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"},
yading@11 131 {CL_INVALID_HOST_PTR, "INVALID HOST PTR"},
yading@11 132 {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"},
yading@11 133 {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"},
yading@11 134 {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"},
yading@11 135 {CL_INVALID_SAMPLER, "INVALID SAMPLER"},
yading@11 136 {CL_INVALID_BINARY, "INVALID BINARY"},
yading@11 137 {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"},
yading@11 138 {CL_INVALID_PROGRAM, "INVALID PROGRAM"},
yading@11 139 {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"},
yading@11 140 {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"},
yading@11 141 {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"},
yading@11 142 {CL_INVALID_KERNEL, "INVALID KERNEL"},
yading@11 143 {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"},
yading@11 144 {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"},
yading@11 145 {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"},
yading@11 146 {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"},
yading@11 147 {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"},
yading@11 148 {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"},
yading@11 149 {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"},
yading@11 150 {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"},
yading@11 151 {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"},
yading@11 152 {CL_INVALID_EVENT, "INVALID EVENT"},
yading@11 153 {CL_INVALID_OPERATION, "INVALID OPERATION"},
yading@11 154 {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"},
yading@11 155 {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"},
yading@11 156 {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"},
yading@11 157 {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"},
yading@11 158 {CL_INVALID_PROPERTY, "INVALID PROPERTY"},
yading@11 159 {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"},
yading@11 160 {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"},
yading@11 161 {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"},
yading@11 162 {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"},
yading@11 163 };
yading@11 164
yading@11 165 static const char *opencl_errstr(cl_int status)
yading@11 166 {
yading@11 167 int i;
yading@11 168 for (i = 0; i < sizeof(opencl_err_msg); i++) {
yading@11 169 if (opencl_err_msg[i].err_code == status)
yading@11 170 return opencl_err_msg[i].err_str;
yading@11 171 }
yading@11 172 return "unknown error";
yading@11 173 }
yading@11 174
yading@11 175 static void free_device_list(AVOpenCLDeviceList *device_list)
yading@11 176 {
yading@11 177 int i, j;
yading@11 178 if (!device_list)
yading@11 179 return;
yading@11 180 for (i = 0; i < device_list->platform_num; i++) {
yading@11 181 if (!device_list->platform_node[i])
yading@11 182 continue;
yading@11 183 for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
yading@11 184 av_freep(&(device_list->platform_node[i]->device_node[j]));
yading@11 185 }
yading@11 186 av_freep(&device_list->platform_node[i]->device_node);
yading@11 187 av_freep(&device_list->platform_node[i]);
yading@11 188 }
yading@11 189 av_freep(&device_list->platform_node);
yading@11 190 device_list->platform_num = 0;
yading@11 191 }
yading@11 192
yading@11 193 static int get_device_list(AVOpenCLDeviceList *device_list)
yading@11 194 {
yading@11 195 cl_int status;
yading@11 196 int i, j, k, device_num, total_devices_num,ret = 0;
yading@11 197 int *devices_num;
yading@11 198 cl_platform_id *platform_ids = NULL;
yading@11 199 cl_device_id *device_ids = NULL;
yading@11 200 AVOpenCLDeviceNode *device_node = NULL;
yading@11 201 status = clGetPlatformIDs(0, NULL, &device_list->platform_num);
yading@11 202 if (status != CL_SUCCESS) {
yading@11 203 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 204 "Could not get OpenCL platform ids: %s\n", opencl_errstr(status));
yading@11 205 return AVERROR_EXTERNAL;
yading@11 206 }
yading@11 207 platform_ids = av_mallocz(device_list->platform_num * sizeof(cl_platform_id));
yading@11 208 if (!platform_ids)
yading@11 209 return AVERROR(ENOMEM);
yading@11 210 status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL);
yading@11 211 if (status != CL_SUCCESS) {
yading@11 212 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 213 "Could not get OpenCL platform ids: %s\n", opencl_errstr(status));
yading@11 214 ret = AVERROR_EXTERNAL;
yading@11 215 goto end;
yading@11 216 }
yading@11 217 device_list->platform_node = av_mallocz(device_list->platform_num * sizeof(AVOpenCLPlatformNode *));
yading@11 218 if (!device_list->platform_node) {
yading@11 219 ret = AVERROR(ENOMEM);
yading@11 220 goto end;
yading@11 221 }
yading@11 222 devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type));
yading@11 223 if (!devices_num) {
yading@11 224 ret = AVERROR(ENOMEM);
yading@11 225 goto end;
yading@11 226 }
yading@11 227 for (i = 0; i < device_list->platform_num; i++) {
yading@11 228 device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode));
yading@11 229 if (!device_list->platform_node[i]) {
yading@11 230 ret = AVERROR(ENOMEM);
yading@11 231 goto end;
yading@11 232 }
yading@11 233 device_list->platform_node[i]->platform_id = platform_ids[i];
yading@11 234 status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
yading@11 235 sizeof(device_list->platform_node[i]->platform_name),
yading@11 236 device_list->platform_node[i]->platform_name, NULL);
yading@11 237 total_devices_num = 0;
yading@11 238 for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
yading@11 239 status = clGetDeviceIDs(device_list->platform_node[i]->platform_id,
yading@11 240 device_type[j], 0, NULL, &devices_num[j]);
yading@11 241 total_devices_num += devices_num[j];
yading@11 242 }
yading@11 243 device_list->platform_node[i]->device_node = av_mallocz(total_devices_num * sizeof(AVOpenCLDeviceNode *));
yading@11 244 if (!device_list->platform_node[i]->device_node) {
yading@11 245 ret = AVERROR(ENOMEM);
yading@11 246 goto end;
yading@11 247 }
yading@11 248 for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
yading@11 249 if (devices_num[j]) {
yading@11 250 device_ids = av_mallocz(devices_num[j] * sizeof(cl_device_id));
yading@11 251 if (!device_ids) {
yading@11 252 ret = AVERROR(ENOMEM);
yading@11 253 goto end;
yading@11 254 }
yading@11 255 status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j],
yading@11 256 devices_num[j], device_ids, NULL);
yading@11 257 if (status != CL_SUCCESS) {
yading@11 258 av_log(&opencl_ctx, AV_LOG_WARNING,
yading@11 259 "Could not get device ID: %s:\n", opencl_errstr(status));
yading@11 260 av_freep(&device_ids);
yading@11 261 continue;
yading@11 262 }
yading@11 263 for (k = 0; k < devices_num[j]; k++) {
yading@11 264 device_num = device_list->platform_node[i]->device_num;
yading@11 265 device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode));
yading@11 266 if (!device_list->platform_node[i]->device_node[device_num]) {
yading@11 267 ret = AVERROR(ENOMEM);
yading@11 268 goto end;
yading@11 269 }
yading@11 270 device_node = device_list->platform_node[i]->device_node[device_num];
yading@11 271 device_node->device_id = device_ids[k];
yading@11 272 device_node->device_type = device_type[j];
yading@11 273 status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
yading@11 274 sizeof(device_node->device_name), device_node->device_name,
yading@11 275 NULL);
yading@11 276 if (status != CL_SUCCESS) {
yading@11 277 av_log(&opencl_ctx, AV_LOG_WARNING,
yading@11 278 "Could not get device name: %s\n", opencl_errstr(status));
yading@11 279 continue;
yading@11 280 }
yading@11 281 device_list->platform_node[i]->device_num++;
yading@11 282 }
yading@11 283 av_freep(&device_ids);
yading@11 284 }
yading@11 285 }
yading@11 286 }
yading@11 287 end:
yading@11 288 av_freep(&platform_ids);
yading@11 289 av_freep(&devices_num);
yading@11 290 av_freep(&device_ids);
yading@11 291 if (ret < 0)
yading@11 292 free_device_list(device_list);
yading@11 293 return ret;
yading@11 294 }
yading@11 295
yading@11 296 int av_opencl_get_device_list(AVOpenCLDeviceList **device_list)
yading@11 297 {
yading@11 298 int ret = 0;
yading@11 299 *device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
yading@11 300 if (!(*device_list)) {
yading@11 301 av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n");
yading@11 302 return AVERROR(ENOMEM);
yading@11 303 }
yading@11 304 ret = get_device_list(*device_list);
yading@11 305 if (ret < 0) {
yading@11 306 av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n");
yading@11 307 free_device_list(*device_list);
yading@11 308 av_freep(device_list);
yading@11 309 return ret;
yading@11 310 }
yading@11 311 return ret;
yading@11 312 }
yading@11 313
yading@11 314 void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
yading@11 315 {
yading@11 316 free_device_list(*device_list);
yading@11 317 av_freep(device_list);
yading@11 318 }
yading@11 319
yading@11 320 int av_opencl_set_option(const char *key, const char *val)
yading@11 321 {
yading@11 322 int ret = 0;
yading@11 323 LOCK_OPENCL
yading@11 324 if (!opencl_ctx.opt_init_flag) {
yading@11 325 av_opt_set_defaults(&opencl_ctx);
yading@11 326 opencl_ctx.opt_init_flag = 1;
yading@11 327 }
yading@11 328 ret = av_opt_set(&opencl_ctx, key, val, 0);
yading@11 329 UNLOCK_OPENCL
yading@11 330 return ret;
yading@11 331 }
yading@11 332
yading@11 333 int av_opencl_get_option(const char *key, uint8_t **out_val)
yading@11 334 {
yading@11 335 int ret = 0;
yading@11 336 LOCK_OPENCL
yading@11 337 ret = av_opt_get(&opencl_ctx, key, 0, out_val);
yading@11 338 UNLOCK_OPENCL
yading@11 339 return ret;
yading@11 340 }
yading@11 341
yading@11 342 void av_opencl_free_option(void)
yading@11 343 {
yading@11 344 /*FIXME: free openclutils context*/
yading@11 345 LOCK_OPENCL
yading@11 346 av_opt_free(&opencl_ctx);
yading@11 347 UNLOCK_OPENCL
yading@11 348 }
yading@11 349
yading@11 350 AVOpenCLExternalEnv *av_opencl_alloc_external_env(void)
yading@11 351 {
yading@11 352 AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv));
yading@11 353 if (!ext) {
yading@11 354 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 355 "Could not malloc external opencl environment data space\n");
yading@11 356 }
yading@11 357 return ext;
yading@11 358 }
yading@11 359
yading@11 360 void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env)
yading@11 361 {
yading@11 362 av_freep(ext_opencl_env);
yading@11 363 }
yading@11 364
yading@11 365 int av_opencl_register_kernel_code(const char *kernel_code)
yading@11 366 {
yading@11 367 int i, ret = 0;
yading@11 368 LOCK_OPENCL;
yading@11 369 if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) {
yading@11 370 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 371 "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
yading@11 372 MAX_KERNEL_CODE_NUM);
yading@11 373 ret = AVERROR(EINVAL);
yading@11 374 goto end;
yading@11 375 }
yading@11 376 for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
yading@11 377 if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) {
yading@11 378 av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n");
yading@11 379 goto end;
yading@11 380 }
yading@11 381 }
yading@11 382 opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code;
yading@11 383 opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0;
yading@11 384 opencl_ctx.kernel_code_count++;
yading@11 385 end:
yading@11 386 UNLOCK_OPENCL;
yading@11 387 return ret;
yading@11 388 }
yading@11 389
yading@11 390 int av_opencl_create_kernel(AVOpenCLKernelEnv *env, const char *kernel_name)
yading@11 391 {
yading@11 392 cl_int status;
yading@11 393 int i, ret = 0;
yading@11 394 LOCK_OPENCL;
yading@11 395 if (strlen(kernel_name) + 1 > AV_OPENCL_MAX_KERNEL_NAME_SIZE) {
yading@11 396 av_log(&opencl_ctx, AV_LOG_ERROR, "Created kernel name %s is too long\n", kernel_name);
yading@11 397 ret = AVERROR(EINVAL);
yading@11 398 goto end;
yading@11 399 }
yading@11 400 if (!env->kernel) {
yading@11 401 if (opencl_ctx.kernel_count >= MAX_KERNEL_NUM) {
yading@11 402 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 403 "Could not create kernel with name '%s', maximum number of kernels %d already reached\n",
yading@11 404 kernel_name, MAX_KERNEL_NUM);
yading@11 405 ret = AVERROR(EINVAL);
yading@11 406 goto end;
yading@11 407 }
yading@11 408 if (opencl_ctx.program_count == 0) {
yading@11 409 av_log(&opencl_ctx, AV_LOG_ERROR, "Program count of OpenCL is 0, can not create kernel\n");
yading@11 410 ret = AVERROR(EINVAL);
yading@11 411 goto end;
yading@11 412 }
yading@11 413 for (i = 0; i < opencl_ctx.program_count; i++) {
yading@11 414 env->kernel = clCreateKernel(opencl_ctx.programs[i], kernel_name, &status);
yading@11 415 if (status == CL_SUCCESS)
yading@11 416 break;
yading@11 417 }
yading@11 418 if (status != CL_SUCCESS) {
yading@11 419 av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL kernel: %s\n", opencl_errstr(status));
yading@11 420 ret = AVERROR_EXTERNAL;
yading@11 421 goto end;
yading@11 422 }
yading@11 423 opencl_ctx.kernel_count++;
yading@11 424 env->command_queue = opencl_ctx.command_queue;
yading@11 425 av_strlcpy(env->kernel_name, kernel_name, sizeof(env->kernel_name));
yading@11 426 }
yading@11 427 end:
yading@11 428 UNLOCK_OPENCL;
yading@11 429 return ret;
yading@11 430 }
yading@11 431
yading@11 432 void av_opencl_release_kernel(AVOpenCLKernelEnv *env)
yading@11 433 {
yading@11 434 cl_int status;
yading@11 435 LOCK_OPENCL
yading@11 436 if (!env->kernel)
yading@11 437 goto end;
yading@11 438 status = clReleaseKernel(env->kernel);
yading@11 439 if (status != CL_SUCCESS) {
yading@11 440 av_log(&opencl_ctx, AV_LOG_ERROR, "Could not release kernel: %s\n",
yading@11 441 opencl_errstr(status));
yading@11 442 }
yading@11 443 env->kernel = NULL;
yading@11 444 env->command_queue = NULL;
yading@11 445 env->kernel_name[0] = 0;
yading@11 446 opencl_ctx.kernel_count--;
yading@11 447 end:
yading@11 448 UNLOCK_OPENCL
yading@11 449 }
yading@11 450
yading@11 451 static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
yading@11 452 {
yading@11 453 cl_int status;
yading@11 454 cl_context_properties cps[3];
yading@11 455 int i, ret = 0;
yading@11 456 AVOpenCLDeviceNode *device_node = NULL;
yading@11 457
yading@11 458 if (ext_opencl_env) {
yading@11 459 if (opencl_ctx->is_user_created)
yading@11 460 return 0;
yading@11 461 opencl_ctx->platform_id = ext_opencl_env->platform_id;
yading@11 462 opencl_ctx->is_user_created = 1;
yading@11 463 opencl_ctx->command_queue = ext_opencl_env->command_queue;
yading@11 464 opencl_ctx->context = ext_opencl_env->context;
yading@11 465 opencl_ctx->device_id = ext_opencl_env->device_id;
yading@11 466 opencl_ctx->device_type = ext_opencl_env->device_type;
yading@11 467 } else {
yading@11 468 if (!opencl_ctx->is_user_created) {
yading@11 469 if (!opencl_ctx->device_list.platform_num) {
yading@11 470 ret = get_device_list(&opencl_ctx->device_list);
yading@11 471 if (ret < 0) {
yading@11 472 return ret;
yading@11 473 }
yading@11 474 }
yading@11 475 if (opencl_ctx->platform_idx >= 0) {
yading@11 476 if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) {
yading@11 477 av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n");
yading@11 478 return AVERROR(EINVAL);
yading@11 479 }
yading@11 480 if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) {
yading@11 481 av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n",
yading@11 482 opencl_ctx->platform_idx);
yading@11 483 return AVERROR(EINVAL);
yading@11 484 }
yading@11 485 opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id;
yading@11 486 } else {
yading@11 487 /* get a usable platform by default*/
yading@11 488 for (i = 0; i < opencl_ctx->device_list.platform_num; i++) {
yading@11 489 if (opencl_ctx->device_list.platform_node[i]->device_num) {
yading@11 490 opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id;
yading@11 491 opencl_ctx->platform_idx = i;
yading@11 492 break;
yading@11 493 }
yading@11 494 }
yading@11 495 }
yading@11 496 if (!opencl_ctx->platform_id) {
yading@11 497 av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n");
yading@11 498 return AVERROR_EXTERNAL;
yading@11 499 }
yading@11 500 /* get a usable device*/
yading@11 501 if (opencl_ctx->device_idx >= 0) {
yading@11 502 if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) {
yading@11 503 av_log(opencl_ctx, AV_LOG_ERROR,
yading@11 504 "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx);
yading@11 505 return AVERROR(EINVAL);
yading@11 506 }
yading@11 507 } else {
yading@11 508 opencl_ctx->device_idx = 0;
yading@11 509 }
yading@11 510
yading@11 511 device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx];
yading@11 512 opencl_ctx->device_id = device_node->device_id;
yading@11 513 opencl_ctx->device_type = device_node->device_type;
yading@11 514
yading@11 515 /*
yading@11 516 * Use available platform.
yading@11 517 */
yading@11 518 av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, device id: 0x%x\n",
yading@11 519 opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
yading@11 520 (unsigned int)opencl_ctx->device_id);
yading@11 521 cps[0] = CL_CONTEXT_PLATFORM;
yading@11 522 cps[1] = (cl_context_properties)opencl_ctx->platform_id;
yading@11 523 cps[2] = 0;
yading@11 524
yading@11 525 opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type,
yading@11 526 NULL, NULL, &status);
yading@11 527 if (status != CL_SUCCESS) {
yading@11 528 av_log(opencl_ctx, AV_LOG_ERROR,
yading@11 529 "Could not get OpenCL context from device type: %s\n", opencl_errstr(status));
yading@11 530 return AVERROR_EXTERNAL;
yading@11 531 }
yading@11 532 opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id,
yading@11 533 0, &status);
yading@11 534 if (status != CL_SUCCESS) {
yading@11 535 av_log(opencl_ctx, AV_LOG_ERROR,
yading@11 536 "Could not create OpenCL command queue: %s\n", opencl_errstr(status));
yading@11 537 return AVERROR_EXTERNAL;
yading@11 538 }
yading@11 539 }
yading@11 540 }
yading@11 541 return ret;
yading@11 542 }
yading@11 543
yading@11 544 static int compile_kernel_file(OpenclContext *opencl_ctx)
yading@11 545 {
yading@11 546 cl_int status;
yading@11 547 char *temp, *source_str = NULL;
yading@11 548 size_t source_str_len = 0;
yading@11 549 int i, ret = 0;
yading@11 550
yading@11 551 for (i = 0; i < opencl_ctx->kernel_code_count; i++) {
yading@11 552 if (!opencl_ctx->kernel_code[i].is_compiled)
yading@11 553 source_str_len += strlen(opencl_ctx->kernel_code[i].kernel_string);
yading@11 554 }
yading@11 555 if (!source_str_len) {
yading@11 556 return 0;
yading@11 557 }
yading@11 558 source_str = av_mallocz(source_str_len + 1);
yading@11 559 if (!source_str) {
yading@11 560 return AVERROR(ENOMEM);
yading@11 561 }
yading@11 562 temp = source_str;
yading@11 563 for (i = 0; i < opencl_ctx->kernel_code_count; i++) {
yading@11 564 if (!opencl_ctx->kernel_code[i].is_compiled) {
yading@11 565 memcpy(temp, opencl_ctx->kernel_code[i].kernel_string,
yading@11 566 strlen(opencl_ctx->kernel_code[i].kernel_string));
yading@11 567 opencl_ctx->kernel_code[i].is_compiled = 1;
yading@11 568 temp += strlen(opencl_ctx->kernel_code[i].kernel_string);
yading@11 569 }
yading@11 570 }
yading@11 571 /* create a CL program using the kernel source */
yading@11 572 opencl_ctx->programs[opencl_ctx->program_count] = clCreateProgramWithSource(opencl_ctx->context,
yading@11 573 1, (const char **)(&source_str),
yading@11 574 &source_str_len, &status);
yading@11 575 if(status != CL_SUCCESS) {
yading@11 576 av_log(opencl_ctx, AV_LOG_ERROR,
yading@11 577 "Could not create OpenCL program with source code: %s\n", opencl_errstr(status));
yading@11 578 ret = AVERROR_EXTERNAL;
yading@11 579 goto end;
yading@11 580 }
yading@11 581 if (!opencl_ctx->programs[opencl_ctx->program_count]) {
yading@11 582 av_log(opencl_ctx, AV_LOG_ERROR, "Created program is NULL\n");
yading@11 583 ret = AVERROR_EXTERNAL;
yading@11 584 goto end;
yading@11 585 }
yading@11 586 status = clBuildProgram(opencl_ctx->programs[opencl_ctx->program_count], 1, &(opencl_ctx->device_id),
yading@11 587 opencl_ctx->build_options, NULL, NULL);
yading@11 588 if (status != CL_SUCCESS) {
yading@11 589 av_log(opencl_ctx, AV_LOG_ERROR,
yading@11 590 "Could not compile OpenCL kernel: %s\n", opencl_errstr(status));
yading@11 591 ret = AVERROR_EXTERNAL;
yading@11 592 goto end;
yading@11 593 }
yading@11 594 opencl_ctx->program_count++;
yading@11 595 end:
yading@11 596 av_free(source_str);
yading@11 597 return ret;
yading@11 598 }
yading@11 599
yading@11 600 int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
yading@11 601 {
yading@11 602 int ret = 0;
yading@11 603 LOCK_OPENCL
yading@11 604 if (!opencl_ctx.init_count) {
yading@11 605 if (!opencl_ctx.opt_init_flag) {
yading@11 606 av_opt_set_defaults(&opencl_ctx);
yading@11 607 opencl_ctx.opt_init_flag = 1;
yading@11 608 }
yading@11 609 ret = init_opencl_env(&opencl_ctx, ext_opencl_env);
yading@11 610 if (ret < 0)
yading@11 611 goto end;
yading@11 612 }
yading@11 613 ret = compile_kernel_file(&opencl_ctx);
yading@11 614 if (ret < 0)
yading@11 615 goto end;
yading@11 616 if (opencl_ctx.kernel_code_count <= 0) {
yading@11 617 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 618 "No kernel code is registered, compile kernel file failed\n");
yading@11 619 ret = AVERROR(EINVAL);
yading@11 620 goto end;
yading@11 621 }
yading@11 622 opencl_ctx.init_count++;
yading@11 623
yading@11 624 end:
yading@11 625 UNLOCK_OPENCL
yading@11 626 return ret;
yading@11 627 }
yading@11 628
yading@11 629 void av_opencl_uninit(void)
yading@11 630 {
yading@11 631 cl_int status;
yading@11 632 int i;
yading@11 633 LOCK_OPENCL
yading@11 634 opencl_ctx.init_count--;
yading@11 635 if (opencl_ctx.is_user_created)
yading@11 636 goto end;
yading@11 637 if (opencl_ctx.init_count > 0 || opencl_ctx.kernel_count > 0)
yading@11 638 goto end;
yading@11 639 for (i = 0; i < opencl_ctx.program_count; i++) {
yading@11 640 if (opencl_ctx.programs[i]) {
yading@11 641 status = clReleaseProgram(opencl_ctx.programs[i]);
yading@11 642 if (status != CL_SUCCESS) {
yading@11 643 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 644 "Could not release OpenCL program: %s\n", opencl_errstr(status));
yading@11 645 }
yading@11 646 opencl_ctx.programs[i] = NULL;
yading@11 647 }
yading@11 648 }
yading@11 649 if (opencl_ctx.command_queue) {
yading@11 650 status = clReleaseCommandQueue(opencl_ctx.command_queue);
yading@11 651 if (status != CL_SUCCESS) {
yading@11 652 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 653 "Could not release OpenCL command queue: %s\n", opencl_errstr(status));
yading@11 654 }
yading@11 655 opencl_ctx.command_queue = NULL;
yading@11 656 }
yading@11 657 if (opencl_ctx.context) {
yading@11 658 status = clReleaseContext(opencl_ctx.context);
yading@11 659 if (status != CL_SUCCESS) {
yading@11 660 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 661 "Could not release OpenCL context: %s\n", opencl_errstr(status));
yading@11 662 }
yading@11 663 opencl_ctx.context = NULL;
yading@11 664 }
yading@11 665 free_device_list(&opencl_ctx.device_list);
yading@11 666 end:
yading@11 667 if ((opencl_ctx.init_count <= 0) && (opencl_ctx.kernel_count <= 0))
yading@11 668 av_opt_free(&opencl_ctx); //FIXME: free openclutils context
yading@11 669 UNLOCK_OPENCL
yading@11 670 }
yading@11 671
yading@11 672 int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
yading@11 673 {
yading@11 674 cl_int status;
yading@11 675 *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status);
yading@11 676 if (status != CL_SUCCESS) {
yading@11 677 av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 678 return AVERROR_EXTERNAL;
yading@11 679 }
yading@11 680 return 0;
yading@11 681 }
yading@11 682
yading@11 683 void av_opencl_buffer_release(cl_mem *cl_buf)
yading@11 684 {
yading@11 685 cl_int status = 0;
yading@11 686 if (!cl_buf)
yading@11 687 return;
yading@11 688 status = clReleaseMemObject(*cl_buf);
yading@11 689 if (status != CL_SUCCESS) {
yading@11 690 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 691 "Could not release OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 692 }
yading@11 693 memset(cl_buf, 0, sizeof(*cl_buf));
yading@11 694 }
yading@11 695
yading@11 696 int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
yading@11 697 {
yading@11 698 cl_int status;
yading@11 699 void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
yading@11 700 CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size,
yading@11 701 0, NULL, NULL, &status);
yading@11 702
yading@11 703 if (status != CL_SUCCESS) {
yading@11 704 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 705 "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 706 return AVERROR_EXTERNAL;
yading@11 707 }
yading@11 708 memcpy(mapped, src_buf, buf_size);
yading@11 709
yading@11 710 status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
yading@11 711 if (status != CL_SUCCESS) {
yading@11 712 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 713 "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 714 return AVERROR_EXTERNAL;
yading@11 715 }
yading@11 716 return 0;
yading@11 717 }
yading@11 718
yading@11 719 int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
yading@11 720 {
yading@11 721 cl_int status;
yading@11 722 void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
yading@11 723 CL_TRUE, CL_MAP_READ, 0, buf_size,
yading@11 724 0, NULL, NULL, &status);
yading@11 725
yading@11 726 if (status != CL_SUCCESS) {
yading@11 727 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 728 "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 729 return AVERROR_EXTERNAL;
yading@11 730 }
yading@11 731 memcpy(dst_buf, mapped, buf_size);
yading@11 732
yading@11 733 status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
yading@11 734 if (status != CL_SUCCESS) {
yading@11 735 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 736 "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 737 return AVERROR_EXTERNAL;
yading@11 738 }
yading@11 739 return 0;
yading@11 740 }
yading@11 741
yading@11 742 int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
yading@11 743 uint8_t **src_data, int *plane_size, int plane_num)
yading@11 744 {
yading@11 745 int i, buffer_size = 0;
yading@11 746 uint8_t *temp;
yading@11 747 cl_int status;
yading@11 748 void *mapped;
yading@11 749 if ((unsigned int)plane_num > 8) {
yading@11 750 return AVERROR(EINVAL);
yading@11 751 }
yading@11 752 for (i = 0;i < plane_num;i++) {
yading@11 753 buffer_size += plane_size[i];
yading@11 754 }
yading@11 755 if (buffer_size > cl_buffer_size) {
yading@11 756 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 757 "Cannot write image to OpenCL buffer: buffer too small\n");
yading@11 758 return AVERROR(EINVAL);
yading@11 759 }
yading@11 760 mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
yading@11 761 CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
yading@11 762 0, NULL, NULL, &status);
yading@11 763 if (status != CL_SUCCESS) {
yading@11 764 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 765 "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 766 return AVERROR_EXTERNAL;
yading@11 767 }
yading@11 768 temp = mapped;
yading@11 769 temp += dst_cl_offset;
yading@11 770 for (i = 0; i < plane_num; i++) {
yading@11 771 memcpy(temp, src_data[i], plane_size[i]);
yading@11 772 temp += plane_size[i];
yading@11 773 }
yading@11 774 status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
yading@11 775 if (status != CL_SUCCESS) {
yading@11 776 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 777 "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 778 return AVERROR_EXTERNAL;
yading@11 779 }
yading@11 780 return 0;
yading@11 781 }
yading@11 782
yading@11 783 int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
yading@11 784 cl_mem src_cl_buf, size_t cl_buffer_size)
yading@11 785 {
yading@11 786 int i,buffer_size = 0,ret = 0;
yading@11 787 uint8_t *temp;
yading@11 788 void *mapped;
yading@11 789 cl_int status;
yading@11 790 if ((unsigned int)plane_num > 8) {
yading@11 791 return AVERROR(EINVAL);
yading@11 792 }
yading@11 793 for (i = 0; i < plane_num; i++) {
yading@11 794 buffer_size += plane_size[i];
yading@11 795 }
yading@11 796 if (buffer_size > cl_buffer_size) {
yading@11 797 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 798 "Cannot write image to CPU buffer: OpenCL buffer too small\n");
yading@11 799 return AVERROR(EINVAL);
yading@11 800 }
yading@11 801 mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
yading@11 802 CL_TRUE, CL_MAP_READ, 0, buffer_size,
yading@11 803 0, NULL, NULL, &status);
yading@11 804
yading@11 805 if (status != CL_SUCCESS) {
yading@11 806 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 807 "Could not map OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 808 return AVERROR_EXTERNAL;
yading@11 809 }
yading@11 810 temp = mapped;
yading@11 811 if (ret >= 0) {
yading@11 812 for (i = 0; i < plane_num; i++) {
yading@11 813 memcpy(dst_data[i], temp, plane_size[i]);
yading@11 814 temp += plane_size[i];
yading@11 815 }
yading@11 816 }
yading@11 817 status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
yading@11 818 if (status != CL_SUCCESS) {
yading@11 819 av_log(&opencl_ctx, AV_LOG_ERROR,
yading@11 820 "Could not unmap OpenCL buffer: %s\n", opencl_errstr(status));
yading@11 821 return AVERROR_EXTERNAL;
yading@11 822 }
yading@11 823 return 0;
yading@11 824 }