1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #define CL_USE_DEPRECATED_OPENCL_1_2_APIS
20
21 #include <string.h>
22
23 #include "config.h"
24
25 #include "avassert.h"
26 #include "avstring.h"
27 #include "common.h"
28 #include "hwcontext.h"
29 #include "hwcontext_internal.h"
30 #include "hwcontext_opencl.h"
31 #include "mem.h"
32 #include "pixdesc.h"
33
34 #if HAVE_OPENCL_VAAPI_BEIGNET
35 #include <unistd.h>
36 #include <va/va.h>
37 #include <va/va_drmcommon.h>
38 #include <CL/cl_intel.h>
39 #include "hwcontext_vaapi.h"
40 #endif
41
42 #if HAVE_OPENCL_DRM_BEIGNET
43 #include <unistd.h>
44 #include <CL/cl_intel.h>
45 #include "hwcontext_drm.h"
46 #endif
47
48 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
49 #if CONFIG_LIBMFX
50 #include <mfx/mfxstructures.h>
51 #endif
52 #include <va/va.h>
53 #include <CL/cl_va_api_media_sharing_intel.h>
54 #include "hwcontext_vaapi.h"
55 #endif
56
57 #if HAVE_OPENCL_DXVA2
58 #define COBJMACROS
59 #include <CL/cl_dx9_media_sharing.h>
60 #include <dxva2api.h>
61 #include "hwcontext_dxva2.h"
62 #endif
63
64 #if HAVE_OPENCL_D3D11
65 #include <CL/cl_d3d11.h>
66 #include "hwcontext_d3d11va.h"
67 #endif
68
69 #if HAVE_OPENCL_DRM_ARM
70 #include <CL/cl_ext.h>
71 #include <drm_fourcc.h>
72 #include "hwcontext_drm.h"
73 #endif
74
75
76 typedef struct OpenCLDeviceContext {
77 // Default command queue to use for transfer/mapping operations on
78 // the device. If the user supplies one, this is a reference to it.
79 // Otherwise, it is newly-created.
80 cl_command_queue command_queue;
81
82 // The platform the context exists on. This is needed to query and
83 // retrieve extension functions.
84 cl_platform_id platform_id;
85
86 // Platform/device-specific functions.
87 #if HAVE_OPENCL_DRM_BEIGNET
88 int beignet_drm_mapping_usable;
89 clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL;
90 #endif
91
92 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
93 int qsv_mapping_usable;
94 clCreateFromVA_APIMediaSurfaceINTEL_fn
95 clCreateFromVA_APIMediaSurfaceINTEL;
96 clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
97 clEnqueueAcquireVA_APIMediaSurfacesINTEL;
98 clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
99 clEnqueueReleaseVA_APIMediaSurfacesINTEL;
100 #endif
101
102 #if HAVE_OPENCL_DXVA2
103 int dxva2_mapping_usable;
104 cl_dx9_media_adapter_type_khr dx9_media_adapter_type;
105
106 clCreateFromDX9MediaSurfaceKHR_fn
107 clCreateFromDX9MediaSurfaceKHR;
108 clEnqueueAcquireDX9MediaSurfacesKHR_fn
109 clEnqueueAcquireDX9MediaSurfacesKHR;
110 clEnqueueReleaseDX9MediaSurfacesKHR_fn
111 clEnqueueReleaseDX9MediaSurfacesKHR;
112 #endif
113
114 #if HAVE_OPENCL_D3D11
115 int d3d11_mapping_usable;
116 clCreateFromD3D11Texture2DKHR_fn
117 clCreateFromD3D11Texture2DKHR;
118 clEnqueueAcquireD3D11ObjectsKHR_fn
119 clEnqueueAcquireD3D11ObjectsKHR;
120 clEnqueueReleaseD3D11ObjectsKHR_fn
121 clEnqueueReleaseD3D11ObjectsKHR;
122 #endif
123
124 #if HAVE_OPENCL_DRM_ARM
125 int drm_arm_mapping_usable;
126 #endif
127 } OpenCLDeviceContext;
128
129 typedef struct OpenCLFramesContext {
130 // Command queue used for transfer/mapping operations on this frames
131 // context. If the user supplies one, this is a reference to it.
132 // Otherwise, it is a reference to the default command queue for the
133 // device.
134 cl_command_queue command_queue;
135
136 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
137 // For mapping APIs which have separate creation and acquire/release
138 // steps, this stores the OpenCL memory objects corresponding to each
139 // frame.
140 int nb_mapped_frames;
141 AVOpenCLFrameDescriptor *mapped_frames;
142 #endif
143 } OpenCLFramesContext;
144
145
opencl_error_callback(const char * errinfo,const void * private_info,size_t cb,void * user_data)146 static void CL_CALLBACK opencl_error_callback(const char *errinfo,
147 const void *private_info,
148 size_t cb,
149 void *user_data)
150 {
151 AVHWDeviceContext *ctx = user_data;
152 av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
153 }
154
opencl_device_free(AVHWDeviceContext * hwdev)155 static void opencl_device_free(AVHWDeviceContext *hwdev)
156 {
157 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
158 cl_int cle;
159
160 cle = clReleaseContext(hwctx->context);
161 if (cle != CL_SUCCESS) {
162 av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
163 "context: %d.\n", cle);
164 }
165 }
166
167 static struct {
168 const char *key;
169 cl_platform_info name;
170 } opencl_platform_params[] = {
171 { "platform_profile", CL_PLATFORM_PROFILE },
172 { "platform_version", CL_PLATFORM_VERSION },
173 { "platform_name", CL_PLATFORM_NAME },
174 { "platform_vendor", CL_PLATFORM_VENDOR },
175 { "platform_extensions", CL_PLATFORM_EXTENSIONS },
176 };
177
178 static struct {
179 const char *key;
180 cl_device_info name;
181 } opencl_device_params[] = {
182 { "device_name", CL_DEVICE_NAME },
183 { "device_vendor", CL_DEVICE_VENDOR },
184 { "driver_version", CL_DRIVER_VERSION },
185 { "device_version", CL_DEVICE_VERSION },
186 { "device_profile", CL_DEVICE_PROFILE },
187 { "device_extensions", CL_DEVICE_EXTENSIONS },
188 };
189
190 static struct {
191 const char *key;
192 cl_device_type type;
193 } opencl_device_types[] = {
194 { "cpu", CL_DEVICE_TYPE_CPU },
195 { "gpu", CL_DEVICE_TYPE_GPU },
196 { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
197 { "custom", CL_DEVICE_TYPE_CUSTOM },
198 { "default", CL_DEVICE_TYPE_DEFAULT },
199 { "all", CL_DEVICE_TYPE_ALL },
200 };
201
opencl_get_platform_string(cl_platform_id platform_id,cl_platform_info key)202 static char *opencl_get_platform_string(cl_platform_id platform_id,
203 cl_platform_info key)
204 {
205 char *str;
206 size_t size;
207 cl_int cle;
208 cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
209 if (cle != CL_SUCCESS)
210 return NULL;
211 str = av_malloc(size);
212 if (!str)
213 return NULL;
214 cle = clGetPlatformInfo(platform_id, key, size, str, &size);
215 if (cle != CL_SUCCESS) {
216 av_free(str);
217 return NULL;
218 }
219 av_assert0(strlen(str) + 1 == size);
220 return str;
221 }
222
opencl_get_device_string(cl_device_id device_id,cl_device_info key)223 static char *opencl_get_device_string(cl_device_id device_id,
224 cl_device_info key)
225 {
226 char *str;
227 size_t size;
228 cl_int cle;
229 cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
230 if (cle != CL_SUCCESS)
231 return NULL;
232 str = av_malloc(size);
233 if (!str)
234 return NULL;
235 cle = clGetDeviceInfo(device_id, key, size, str, &size);
236 if (cle != CL_SUCCESS) {
237 av_free(str);
238 return NULL;
239 }
240 av_assert0(strlen(str) + 1== size);
241 return str;
242 }
243
opencl_check_platform_extension(cl_platform_id platform_id,const char * name)244 static int opencl_check_platform_extension(cl_platform_id platform_id,
245 const char *name)
246 {
247 char *str;
248 int found = 0;
249 str = opencl_get_platform_string(platform_id,
250 CL_PLATFORM_EXTENSIONS);
251 if (str && strstr(str, name))
252 found = 1;
253 av_free(str);
254 return found;
255 }
256
opencl_check_device_extension(cl_device_id device_id,const char * name)257 static int opencl_check_device_extension(cl_device_id device_id,
258 const char *name)
259 {
260 char *str;
261 int found = 0;
262 str = opencl_get_device_string(device_id,
263 CL_DEVICE_EXTENSIONS);
264 if (str && strstr(str, name))
265 found = 1;
266 av_free(str);
267 return found;
268 }
269
opencl_check_extension(AVHWDeviceContext * hwdev,const char * name)270 static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
271 const char *name)
272 {
273 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
274 OpenCLDeviceContext *priv = hwdev->internal->priv;
275
276 if (opencl_check_platform_extension(priv->platform_id, name)) {
277 av_log(hwdev, AV_LOG_DEBUG,
278 "%s found as platform extension.\n", name);
279 return 1;
280 }
281
282 if (opencl_check_device_extension(hwctx->device_id, name)) {
283 av_log(hwdev, AV_LOG_DEBUG,
284 "%s found as device extension.\n", name);
285 return 1;
286 }
287
288 return 0;
289 }
290
opencl_enumerate_platforms(AVHWDeviceContext * hwdev,cl_uint * nb_platforms,cl_platform_id ** platforms,void * context)291 static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
292 cl_uint *nb_platforms,
293 cl_platform_id **platforms,
294 void *context)
295 {
296 cl_int cle;
297
298 cle = clGetPlatformIDs(0, NULL, nb_platforms);
299 if (cle != CL_SUCCESS) {
300 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
301 "OpenCL platforms: %d.\n", cle);
302 return AVERROR(ENODEV);
303 }
304 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
305 *nb_platforms);
306
307 *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
308 if (!*platforms)
309 return AVERROR(ENOMEM);
310
311 cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
312 if (cle != CL_SUCCESS) {
313 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
314 "platforms: %d.\n", cle);
315 av_freep(platforms);
316 return AVERROR(ENODEV);
317 }
318
319 return 0;
320 }
321
opencl_filter_platform(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,void * context)322 static int opencl_filter_platform(AVHWDeviceContext *hwdev,
323 cl_platform_id platform_id,
324 const char *platform_name,
325 void *context)
326 {
327 AVDictionary *opts = context;
328 const AVDictionaryEntry *param;
329 char *str;
330 int i, ret = 0;
331
332 for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
333 param = av_dict_get(opts, opencl_platform_params[i].key,
334 NULL, 0);
335 if (!param)
336 continue;
337
338 str = opencl_get_platform_string(platform_id,
339 opencl_platform_params[i].name);
340 if (!str) {
341 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
342 "of platform \"%s\".\n",
343 opencl_platform_params[i].key, platform_name);
344 return AVERROR_UNKNOWN;
345 }
346 if (!av_stristr(str, param->value)) {
347 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
348 param->key, str);
349 ret = 1;
350 }
351 av_free(str);
352 }
353
354 return ret;
355 }
356
opencl_enumerate_devices(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,cl_uint * nb_devices,cl_device_id ** devices,void * context)357 static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
358 cl_platform_id platform_id,
359 const char *platform_name,
360 cl_uint *nb_devices,
361 cl_device_id **devices,
362 void *context)
363 {
364 cl_int cle;
365
366 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
367 0, NULL, nb_devices);
368 if (cle == CL_DEVICE_NOT_FOUND) {
369 av_log(hwdev, AV_LOG_DEBUG, "No devices found "
370 "on platform \"%s\".\n", platform_name);
371 *nb_devices = 0;
372 return 0;
373 } else if (cle != CL_SUCCESS) {
374 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
375 "on platform \"%s\": %d.\n", platform_name, cle);
376 return AVERROR(ENODEV);
377 }
378 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
379 "platform \"%s\".\n", *nb_devices, platform_name);
380
381 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
382 if (!*devices)
383 return AVERROR(ENOMEM);
384
385 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
386 *nb_devices, *devices, NULL);
387 if (cle != CL_SUCCESS) {
388 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
389 "on platform \"%s\": %d.\n", platform_name, cle);
390 av_freep(devices);
391 return AVERROR(ENODEV);
392 }
393
394 return 0;
395 }
396
opencl_filter_device(AVHWDeviceContext * hwdev,cl_device_id device_id,const char * device_name,void * context)397 static int opencl_filter_device(AVHWDeviceContext *hwdev,
398 cl_device_id device_id,
399 const char *device_name,
400 void *context)
401 {
402 AVDictionary *opts = context;
403 const AVDictionaryEntry *param;
404 char *str;
405 int i, ret = 0;
406
407 param = av_dict_get(opts, "device_type", NULL, 0);
408 if (param) {
409 cl_device_type match_type = 0, device_type;
410 cl_int cle;
411
412 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
413 if (!strcmp(opencl_device_types[i].key, param->value)) {
414 match_type = opencl_device_types[i].type;
415 break;
416 }
417 }
418 if (!match_type) {
419 av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
420 param->value);
421 return AVERROR(EINVAL);
422 }
423
424 cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
425 sizeof(device_type), &device_type, NULL);
426 if (cle != CL_SUCCESS) {
427 av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
428 "of device \"%s\".\n", device_name);
429 return AVERROR_UNKNOWN;
430 }
431
432 if (!(device_type & match_type)) {
433 av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
434 return 1;
435 }
436 }
437
438 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
439 param = av_dict_get(opts, opencl_device_params[i].key,
440 NULL, 0);
441 if (!param)
442 continue;
443
444 str = opencl_get_device_string(device_id,
445 opencl_device_params[i].name);
446 if (!str) {
447 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
448 "of device \"%s\".\n",
449 opencl_device_params[i].key, device_name);
450 return AVERROR_UNKNOWN;
451 }
452 if (!av_stristr(str, param->value)) {
453 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
454 param->key, str);
455 ret = 1;
456 }
457 av_free(str);
458 }
459
460 return ret;
461 }
462
463 typedef struct OpenCLDeviceSelector {
464 int platform_index;
465 int device_index;
466 void *context;
467 int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
468 cl_uint *nb_platforms,
469 cl_platform_id **platforms,
470 void *context);
471 int (*filter_platform) (AVHWDeviceContext *hwdev,
472 cl_platform_id platform_id,
473 const char *platform_name,
474 void *context);
475 int (*enumerate_devices) (AVHWDeviceContext *hwdev,
476 cl_platform_id platform_id,
477 const char *platform_name,
478 cl_uint *nb_devices,
479 cl_device_id **devices,
480 void *context);
481 int (*filter_device) (AVHWDeviceContext *hwdev,
482 cl_device_id device_id,
483 const char *device_name,
484 void *context);
485 } OpenCLDeviceSelector;
486
opencl_device_create_internal(AVHWDeviceContext * hwdev,const OpenCLDeviceSelector * selector,cl_context_properties * props)487 static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
488 const OpenCLDeviceSelector *selector,
489 cl_context_properties *props)
490 {
491 cl_uint nb_platforms;
492 cl_platform_id *platforms = NULL;
493 cl_platform_id platform_id;
494 cl_uint nb_devices;
495 cl_device_id *devices = NULL;
496 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
497 cl_int cle;
498 cl_context_properties default_props[3];
499 char *platform_name_src = NULL,
500 *device_name_src = NULL;
501 int err, found, p, d;
502
503 av_assert0(selector->enumerate_platforms &&
504 selector->enumerate_devices);
505
506 err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
507 selector->context);
508 if (err)
509 return err;
510
511 found = 0;
512 for (p = 0; p < nb_platforms; p++) {
513 const char *platform_name;
514
515 if (selector->platform_index >= 0 &&
516 selector->platform_index != p)
517 continue;
518
519 av_freep(&platform_name_src);
520 platform_name_src = opencl_get_platform_string(platforms[p],
521 CL_PLATFORM_NAME);
522 if (platform_name_src)
523 platform_name = platform_name_src;
524 else
525 platform_name = "Unknown Platform";
526
527 if (selector->filter_platform) {
528 err = selector->filter_platform(hwdev, platforms[p],
529 platform_name,
530 selector->context);
531 if (err < 0)
532 goto fail;
533 if (err > 0)
534 continue;
535 }
536
537 err = selector->enumerate_devices(hwdev, platforms[p], platform_name,
538 &nb_devices, &devices,
539 selector->context);
540 if (err < 0)
541 continue;
542
543 for (d = 0; d < nb_devices; d++) {
544 const char *device_name;
545
546 if (selector->device_index >= 0 &&
547 selector->device_index != d)
548 continue;
549
550 av_freep(&device_name_src);
551 device_name_src = opencl_get_device_string(devices[d],
552 CL_DEVICE_NAME);
553 if (device_name_src)
554 device_name = device_name_src;
555 else
556 device_name = "Unknown Device";
557
558 if (selector->filter_device) {
559 err = selector->filter_device(hwdev, devices[d],
560 device_name,
561 selector->context);
562 if (err < 0)
563 goto fail;
564 if (err > 0)
565 continue;
566 }
567
568 av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
569 platform_name, device_name);
570
571 ++found;
572 platform_id = platforms[p];
573 hwctx->device_id = devices[d];
574 }
575
576 av_freep(&devices);
577 }
578
579 if (found == 0) {
580 av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
581 err = AVERROR(ENODEV);
582 goto fail;
583 }
584 if (found > 1) {
585 av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
586 err = AVERROR(ENODEV);
587 goto fail;
588 }
589
590 if (!props) {
591 props = default_props;
592 default_props[0] = CL_CONTEXT_PLATFORM;
593 default_props[1] = (intptr_t)platform_id;
594 default_props[2] = 0;
595 } else {
596 if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
597 props[1] = (intptr_t)platform_id;
598 }
599
600 hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
601 &opencl_error_callback, hwdev, &cle);
602 if (!hwctx->context) {
603 av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
604 "%d.\n", cle);
605 err = AVERROR(ENODEV);
606 goto fail;
607 }
608
609 hwdev->free = &opencl_device_free;
610
611 err = 0;
612 fail:
613 av_freep(&platform_name_src);
614 av_freep(&device_name_src);
615 av_freep(&platforms);
616 av_freep(&devices);
617 return err;
618 }
619
opencl_device_create(AVHWDeviceContext * hwdev,const char * device,AVDictionary * opts,int flags)620 static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
621 AVDictionary *opts, int flags)
622 {
623 OpenCLDeviceSelector selector = {
624 .context = opts,
625 .enumerate_platforms = &opencl_enumerate_platforms,
626 .filter_platform = &opencl_filter_platform,
627 .enumerate_devices = &opencl_enumerate_devices,
628 .filter_device = &opencl_filter_device,
629 };
630
631 if (device && device[0]) {
632 // Match one or both indices for platform and device.
633 int d = -1, p = -1, ret;
634 if (device[0] == '.')
635 ret = sscanf(device, ".%d", &d);
636 else
637 ret = sscanf(device, "%d.%d", &p, &d);
638 if (ret < 1) {
639 av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
640 "index specification \"%s\".\n", device);
641 return AVERROR(EINVAL);
642 }
643 selector.platform_index = p;
644 selector.device_index = d;
645 } else {
646 selector.platform_index = -1;
647 selector.device_index = -1;
648 }
649
650 return opencl_device_create_internal(hwdev, &selector, NULL);
651 }
652
opencl_device_init(AVHWDeviceContext * hwdev)653 static int opencl_device_init(AVHWDeviceContext *hwdev)
654 {
655 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
656 OpenCLDeviceContext *priv = hwdev->internal->priv;
657 cl_int cle;
658
659 if (hwctx->command_queue) {
660 cle = clRetainCommandQueue(hwctx->command_queue);
661 if (cle != CL_SUCCESS) {
662 av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
663 "command queue: %d.\n", cle);
664 return AVERROR(EIO);
665 }
666 priv->command_queue = hwctx->command_queue;
667 } else {
668 priv->command_queue = clCreateCommandQueue(hwctx->context,
669 hwctx->device_id,
670 0, &cle);
671 if (!priv->command_queue) {
672 av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
673 "command queue: %d.\n", cle);
674 return AVERROR(EIO);
675 }
676 }
677
678 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
679 sizeof(priv->platform_id), &priv->platform_id,
680 NULL);
681 if (cle != CL_SUCCESS) {
682 av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
683 "platform containing the device.\n");
684 return AVERROR(EIO);
685 }
686
687 #define CL_FUNC(name, desc) do { \
688 if (fail) \
689 break; \
690 priv->name = clGetExtensionFunctionAddressForPlatform( \
691 priv->platform_id, #name); \
692 if (!priv->name) { \
693 av_log(hwdev, AV_LOG_VERBOSE, \
694 desc " function not found (%s).\n", #name); \
695 fail = 1; \
696 } else { \
697 av_log(hwdev, AV_LOG_VERBOSE, \
698 desc " function found (%s).\n", #name); \
699 } \
700 } while (0)
701
702 #if HAVE_OPENCL_DRM_BEIGNET
703 {
704 int fail = 0;
705
706 CL_FUNC(clCreateImageFromFdINTEL,
707 "Beignet DRM to OpenCL image mapping");
708
709 if (fail) {
710 av_log(hwdev, AV_LOG_WARNING, "Beignet DRM to OpenCL "
711 "mapping not usable.\n");
712 priv->beignet_drm_mapping_usable = 0;
713 } else {
714 priv->beignet_drm_mapping_usable = 1;
715 }
716 }
717 #endif
718
719 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
720 {
721 size_t props_size;
722 cl_context_properties *props = NULL;
723 VADisplay va_display;
724 const char *va_ext = "cl_intel_va_api_media_sharing";
725 int i, fail = 0;
726
727 if (!opencl_check_extension(hwdev, va_ext)) {
728 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
729 "required for QSV to OpenCL mapping.\n", va_ext);
730 goto no_qsv;
731 }
732
733 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
734 0, NULL, &props_size);
735 if (cle != CL_SUCCESS) {
736 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
737 "properties: %d.\n", cle);
738 goto no_qsv;
739 }
740 if (props_size == 0) {
741 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
742 "enabled on context creation to use QSV to "
743 "OpenCL mapping.\n");
744 goto no_qsv;
745 }
746
747 props = av_malloc(props_size);
748 if (!props)
749 return AVERROR(ENOMEM);
750
751 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
752 props_size, props, NULL);
753 if (cle != CL_SUCCESS) {
754 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
755 "properties: %d.\n", cle);
756 goto no_qsv;
757 }
758
759 va_display = NULL;
760 for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
761 if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
762 va_display = (VADisplay)(intptr_t)props[i+1];
763 break;
764 }
765 }
766 if (!va_display) {
767 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
768 "enabled on context creation to use QSV to "
769 "OpenCL mapping.\n");
770 goto no_qsv;
771 }
772 if (!vaDisplayIsValid(va_display)) {
773 av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is "
774 "required on context creation to use QSV to "
775 "OpenCL mapping.\n");
776 goto no_qsv;
777 }
778
779 CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
780 "Intel QSV to OpenCL mapping");
781 CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
782 "Intel QSV in OpenCL acquire");
783 CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
784 "Intel QSV in OpenCL release");
785
786 if (fail) {
787 no_qsv:
788 av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping "
789 "not usable.\n");
790 priv->qsv_mapping_usable = 0;
791 } else {
792 priv->qsv_mapping_usable = 1;
793 }
794 av_free(props);
795 }
796 #endif
797
798 #if HAVE_OPENCL_DXVA2
799 {
800 int fail = 0;
801
802 CL_FUNC(clCreateFromDX9MediaSurfaceKHR,
803 "DXVA2 to OpenCL mapping");
804 CL_FUNC(clEnqueueAcquireDX9MediaSurfacesKHR,
805 "DXVA2 in OpenCL acquire");
806 CL_FUNC(clEnqueueReleaseDX9MediaSurfacesKHR,
807 "DXVA2 in OpenCL release");
808
809 if (fail) {
810 av_log(hwdev, AV_LOG_WARNING, "DXVA2 to OpenCL mapping "
811 "not usable.\n");
812 priv->dxva2_mapping_usable = 0;
813 } else {
814 priv->dx9_media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
815 priv->dxva2_mapping_usable = 1;
816 }
817 }
818 #endif
819
820 #if HAVE_OPENCL_D3D11
821 {
822 const char *d3d11_ext = "cl_khr_d3d11_sharing";
823 const char *nv12_ext = "cl_intel_d3d11_nv12_media_sharing";
824 int fail = 0;
825
826 if (!opencl_check_extension(hwdev, d3d11_ext)) {
827 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
828 "required for D3D11 to OpenCL mapping.\n", d3d11_ext);
829 fail = 1;
830 } else if (!opencl_check_extension(hwdev, nv12_ext)) {
831 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be "
832 "required for D3D11 to OpenCL mapping.\n", nv12_ext);
833 // Not fatal.
834 }
835
836 CL_FUNC(clCreateFromD3D11Texture2DKHR,
837 "D3D11 to OpenCL mapping");
838 CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR,
839 "D3D11 in OpenCL acquire");
840 CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR,
841 "D3D11 in OpenCL release");
842
843 if (fail) {
844 av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping "
845 "not usable.\n");
846 priv->d3d11_mapping_usable = 0;
847 } else {
848 priv->d3d11_mapping_usable = 1;
849 }
850 }
851 #endif
852
853 #if HAVE_OPENCL_DRM_ARM
854 {
855 const char *drm_arm_ext = "cl_arm_import_memory";
856 const char *image_ext = "cl_khr_image2d_from_buffer";
857 int fail = 0;
858
859 if (!opencl_check_extension(hwdev, drm_arm_ext)) {
860 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
861 "required for DRM to OpenCL mapping on ARM.\n",
862 drm_arm_ext);
863 fail = 1;
864 }
865 if (!opencl_check_extension(hwdev, image_ext)) {
866 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
867 "required for DRM to OpenCL mapping on ARM.\n",
868 image_ext);
869 fail = 1;
870 }
871
872 // clImportMemoryARM() is linked statically.
873
874 if (fail) {
875 av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM "
876 "not usable.\n");
877 priv->drm_arm_mapping_usable = 0;
878 } else {
879 priv->drm_arm_mapping_usable = 1;
880 }
881 }
882 #endif
883
884 #undef CL_FUNC
885
886 return 0;
887 }
888
opencl_device_uninit(AVHWDeviceContext * hwdev)889 static void opencl_device_uninit(AVHWDeviceContext *hwdev)
890 {
891 OpenCLDeviceContext *priv = hwdev->internal->priv;
892 cl_int cle;
893
894 if (priv->command_queue) {
895 cle = clReleaseCommandQueue(priv->command_queue);
896 if (cle != CL_SUCCESS) {
897 av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
898 "command queue reference: %d.\n", cle);
899 }
900 priv->command_queue = NULL;
901 }
902 }
903
904 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,void * context)905 static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev,
906 cl_platform_id platform_id,
907 const char *platform_name,
908 void *context)
909 {
910 // This doesn't exist as a platform extension, so just test whether
911 // the function we will use for device enumeration exists.
912
913 if (!clGetExtensionFunctionAddressForPlatform(platform_id,
914 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) {
915 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the "
916 "VAAPI device enumeration function.\n", platform_name);
917 return 1;
918 } else {
919 return 0;
920 }
921 }
922
opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,cl_uint * nb_devices,cl_device_id ** devices,void * context)923 static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev,
924 cl_platform_id platform_id,
925 const char *platform_name,
926 cl_uint *nb_devices,
927 cl_device_id **devices,
928 void *context)
929 {
930 VADisplay va_display = context;
931 clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn
932 clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
933 cl_int cle;
934
935 clGetDeviceIDsFromVA_APIMediaAdapterINTEL =
936 clGetExtensionFunctionAddressForPlatform(platform_id,
937 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
938 if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) {
939 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
940 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n");
941 return AVERROR_UNKNOWN;
942 }
943
944 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
945 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
946 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices);
947 if (cle == CL_DEVICE_NOT_FOUND) {
948 av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found "
949 "on platform \"%s\".\n", platform_name);
950 *nb_devices = 0;
951 return 0;
952 } else if (cle != CL_SUCCESS) {
953 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
954 "on platform \"%s\": %d.\n", platform_name, cle);
955 return AVERROR_UNKNOWN;
956 }
957
958 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
959 if (!*devices)
960 return AVERROR(ENOMEM);
961
962 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
963 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
964 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL);
965 if (cle != CL_SUCCESS) {
966 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting "
967 "devices on platform \"%s\": %d.\n", platform_name, cle);
968 av_freep(devices);
969 return AVERROR_UNKNOWN;
970 }
971
972 return 0;
973 }
974
opencl_filter_intel_media_vaapi_device(AVHWDeviceContext * hwdev,cl_device_id device_id,const char * device_name,void * context)975 static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev,
976 cl_device_id device_id,
977 const char *device_name,
978 void *context)
979 {
980 const char *va_ext = "cl_intel_va_api_media_sharing";
981
982 if (opencl_check_device_extension(device_id, va_ext)) {
983 return 0;
984 } else {
985 av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
986 "%s extension.\n", device_name, va_ext);
987 return 1;
988 }
989 }
990 #endif
991
992 #if HAVE_OPENCL_DXVA2
opencl_filter_dxva2_platform(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,void * context)993 static int opencl_filter_dxva2_platform(AVHWDeviceContext *hwdev,
994 cl_platform_id platform_id,
995 const char *platform_name,
996 void *context)
997 {
998 const char *dx9_ext = "cl_khr_dx9_media_sharing";
999
1000 if (opencl_check_platform_extension(platform_id, dx9_ext)) {
1001 return 0;
1002 } else {
1003 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
1004 "%s extension.\n", platform_name, dx9_ext);
1005 return 1;
1006 }
1007 }
1008
opencl_enumerate_dxva2_devices(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,cl_uint * nb_devices,cl_device_id ** devices,void * context)1009 static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev,
1010 cl_platform_id platform_id,
1011 const char *platform_name,
1012 cl_uint *nb_devices,
1013 cl_device_id **devices,
1014 void *context)
1015 {
1016 IDirect3DDevice9 *device = context;
1017 clGetDeviceIDsFromDX9MediaAdapterKHR_fn
1018 clGetDeviceIDsFromDX9MediaAdapterKHR;
1019 cl_dx9_media_adapter_type_khr media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
1020 cl_int cle;
1021
1022 clGetDeviceIDsFromDX9MediaAdapterKHR =
1023 clGetExtensionFunctionAddressForPlatform(platform_id,
1024 "clGetDeviceIDsFromDX9MediaAdapterKHR");
1025 if (!clGetDeviceIDsFromDX9MediaAdapterKHR) {
1026 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
1027 "clGetDeviceIDsFromDX9MediaAdapterKHR().\n");
1028 return AVERROR_UNKNOWN;
1029 }
1030
1031 cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
1032 platform_id, 1, &media_adapter_type, (void**)&device,
1033 CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
1034 0, NULL, nb_devices);
1035 if (cle == CL_DEVICE_NOT_FOUND) {
1036 av_log(hwdev, AV_LOG_DEBUG, "No DXVA2-supporting devices found "
1037 "on platform \"%s\".\n", platform_name);
1038 *nb_devices = 0;
1039 return 0;
1040 } else if (cle != CL_SUCCESS) {
1041 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
1042 "on platform \"%s\": %d.\n", platform_name, cle);
1043 return AVERROR_UNKNOWN;
1044 }
1045
1046 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
1047 if (!*devices)
1048 return AVERROR(ENOMEM);
1049
1050 cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
1051 platform_id, 1, &media_adapter_type, (void**)&device,
1052 CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
1053 *nb_devices, *devices, NULL);
1054 if (cle != CL_SUCCESS) {
1055 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of DXVA2-supporting "
1056 "devices on platform \"%s\": %d.\n", platform_name, cle);
1057 av_freep(devices);
1058 return AVERROR_UNKNOWN;
1059 }
1060
1061 return 0;
1062 }
1063 #endif
1064
1065 #if HAVE_OPENCL_D3D11
opencl_filter_d3d11_platform(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,void * context)1066 static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev,
1067 cl_platform_id platform_id,
1068 const char *platform_name,
1069 void *context)
1070 {
1071 const char *d3d11_ext = "cl_khr_d3d11_sharing";
1072
1073 if (opencl_check_platform_extension(platform_id, d3d11_ext)) {
1074 return 0;
1075 } else {
1076 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
1077 "%s extension.\n", platform_name, d3d11_ext);
1078 return 1;
1079 }
1080 }
1081
opencl_enumerate_d3d11_devices(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,cl_uint * nb_devices,cl_device_id ** devices,void * context)1082 static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev,
1083 cl_platform_id platform_id,
1084 const char *platform_name,
1085 cl_uint *nb_devices,
1086 cl_device_id **devices,
1087 void *context)
1088 {
1089 ID3D11Device *device = context;
1090 clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR;
1091 cl_int cle;
1092
1093 clGetDeviceIDsFromD3D11KHR =
1094 clGetExtensionFunctionAddressForPlatform(platform_id,
1095 "clGetDeviceIDsFromD3D11KHR");
1096 if (!clGetDeviceIDsFromD3D11KHR) {
1097 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
1098 "clGetDeviceIDsFromD3D11KHR().\n");
1099 return AVERROR_UNKNOWN;
1100 }
1101
1102 cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1103 CL_D3D11_DEVICE_KHR, device,
1104 CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1105 0, NULL, nb_devices);
1106 if (cle == CL_DEVICE_NOT_FOUND) {
1107 av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found "
1108 "on platform \"%s\".\n", platform_name);
1109 *nb_devices = 0;
1110 return 0;
1111 } else if (cle != CL_SUCCESS) {
1112 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
1113 "on platform \"%s\": %d.\n", platform_name, cle);
1114 return AVERROR_UNKNOWN;
1115 }
1116
1117 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
1118 if (!*devices)
1119 return AVERROR(ENOMEM);
1120
1121 cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1122 CL_D3D11_DEVICE_KHR, device,
1123 CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1124 *nb_devices, *devices, NULL);
1125 if (cle != CL_SUCCESS) {
1126 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting "
1127 "devices on platform \"%s\": %d.\n", platform_name, cle);
1128 av_freep(devices);
1129 return AVERROR_UNKNOWN;
1130 }
1131
1132 return 0;
1133 }
1134 #endif
1135
1136 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
opencl_filter_gpu_device(AVHWDeviceContext * hwdev,cl_device_id device_id,const char * device_name,void * context)1137 static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev,
1138 cl_device_id device_id,
1139 const char *device_name,
1140 void *context)
1141 {
1142 cl_device_type device_type;
1143 cl_int cle;
1144
1145 cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
1146 sizeof(device_type), &device_type, NULL);
1147 if (cle != CL_SUCCESS) {
1148 av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
1149 "of device \"%s\".\n", device_name);
1150 return AVERROR_UNKNOWN;
1151 }
1152 if (!(device_type & CL_DEVICE_TYPE_GPU)) {
1153 av_log(hwdev, AV_LOG_DEBUG, "Device %s skipped (not GPU).\n",
1154 device_name);
1155 return 1;
1156 }
1157
1158 return 0;
1159 }
1160 #endif
1161
1162 #if HAVE_OPENCL_DRM_ARM
opencl_filter_drm_arm_platform(AVHWDeviceContext * hwdev,cl_platform_id platform_id,const char * platform_name,void * context)1163 static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev,
1164 cl_platform_id platform_id,
1165 const char *platform_name,
1166 void *context)
1167 {
1168 const char *drm_arm_ext = "cl_arm_import_memory";
1169
1170 if (opencl_check_platform_extension(platform_id, drm_arm_ext)) {
1171 return 0;
1172 } else {
1173 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
1174 "%s extension.\n", platform_name, drm_arm_ext);
1175 return 1;
1176 }
1177 }
1178
opencl_filter_drm_arm_device(AVHWDeviceContext * hwdev,cl_device_id device_id,const char * device_name,void * context)1179 static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev,
1180 cl_device_id device_id,
1181 const char *device_name,
1182 void *context)
1183 {
1184 const char *drm_arm_ext = "cl_arm_import_memory";
1185
1186 if (opencl_check_device_extension(device_id, drm_arm_ext)) {
1187 return 0;
1188 } else {
1189 av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
1190 "%s extension.\n", device_name, drm_arm_ext);
1191 return 1;
1192 }
1193 }
1194 #endif
1195
opencl_device_derive(AVHWDeviceContext * hwdev,AVHWDeviceContext * src_ctx,AVDictionary * opts,int flags)1196 static int opencl_device_derive(AVHWDeviceContext *hwdev,
1197 AVHWDeviceContext *src_ctx, AVDictionary *opts,
1198 int flags)
1199 {
1200 int err;
1201 switch (src_ctx->type) {
1202
1203 #if HAVE_OPENCL_DRM_BEIGNET
1204 case AV_HWDEVICE_TYPE_DRM:
1205 case AV_HWDEVICE_TYPE_VAAPI:
1206 {
1207 // Surface mapping works via DRM PRIME fds with no special
1208 // initialisation required in advance. This just finds the
1209 // Beignet ICD by name.
1210 AVDictionary *selector_opts = NULL;
1211
1212 err = av_dict_set(&selector_opts, "platform_vendor", "Intel", 0);
1213 if (err >= 0)
1214 err = av_dict_set(&selector_opts, "platform_version", "beignet", 0);
1215 if (err >= 0) {
1216 OpenCLDeviceSelector selector = {
1217 .platform_index = -1,
1218 .device_index = 0,
1219 .context = selector_opts,
1220 .enumerate_platforms = &opencl_enumerate_platforms,
1221 .filter_platform = &opencl_filter_platform,
1222 .enumerate_devices = &opencl_enumerate_devices,
1223 .filter_device = NULL,
1224 };
1225 err = opencl_device_create_internal(hwdev, &selector, NULL);
1226 }
1227 av_dict_free(&selector_opts);
1228 }
1229 break;
1230 #endif
1231
1232 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1233 // The generic code automatically attempts to derive from all
1234 // ancestors of the given device, so we can ignore QSV devices here
1235 // and just consider the inner VAAPI device it was derived from.
1236 case AV_HWDEVICE_TYPE_VAAPI:
1237 {
1238 AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1239 cl_context_properties props[7] = {
1240 CL_CONTEXT_PLATFORM,
1241 0,
1242 CL_CONTEXT_VA_API_DISPLAY_INTEL,
1243 (intptr_t)src_hwctx->display,
1244 CL_CONTEXT_INTEROP_USER_SYNC,
1245 CL_FALSE,
1246 0,
1247 };
1248 OpenCLDeviceSelector selector = {
1249 .platform_index = -1,
1250 .device_index = -1,
1251 .context = src_hwctx->display,
1252 .enumerate_platforms = &opencl_enumerate_platforms,
1253 .filter_platform = &opencl_filter_intel_media_vaapi_platform,
1254 .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices,
1255 .filter_device = &opencl_filter_intel_media_vaapi_device,
1256 };
1257
1258 err = opencl_device_create_internal(hwdev, &selector, props);
1259 }
1260 break;
1261 #endif
1262
1263 #if HAVE_OPENCL_DXVA2
1264 case AV_HWDEVICE_TYPE_DXVA2:
1265 {
1266 AVDXVA2DeviceContext *src_hwctx = src_ctx->hwctx;
1267 IDirect3DDevice9 *device;
1268 HANDLE device_handle;
1269 HRESULT hr;
1270
1271 hr = IDirect3DDeviceManager9_OpenDeviceHandle(src_hwctx->devmgr,
1272 &device_handle);
1273 if (FAILED(hr)) {
1274 av_log(hwdev, AV_LOG_ERROR, "Failed to open device handle "
1275 "for Direct3D9 device: %lx.\n", (unsigned long)hr);
1276 err = AVERROR_UNKNOWN;
1277 break;
1278 }
1279
1280 hr = IDirect3DDeviceManager9_LockDevice(src_hwctx->devmgr,
1281 device_handle,
1282 &device, FALSE);
1283 if (SUCCEEDED(hr)) {
1284 cl_context_properties props[5] = {
1285 CL_CONTEXT_PLATFORM,
1286 0,
1287 CL_CONTEXT_ADAPTER_D3D9EX_KHR,
1288 (intptr_t)device,
1289 0,
1290 };
1291 OpenCLDeviceSelector selector = {
1292 .platform_index = -1,
1293 .device_index = -1,
1294 .context = device,
1295 .enumerate_platforms = &opencl_enumerate_platforms,
1296 .filter_platform = &opencl_filter_dxva2_platform,
1297 .enumerate_devices = &opencl_enumerate_dxva2_devices,
1298 .filter_device = &opencl_filter_gpu_device,
1299 };
1300
1301 err = opencl_device_create_internal(hwdev, &selector, props);
1302
1303 IDirect3DDeviceManager9_UnlockDevice(src_hwctx->devmgr,
1304 device_handle, FALSE);
1305 } else {
1306 av_log(hwdev, AV_LOG_ERROR, "Failed to lock device handle "
1307 "for Direct3D9 device: %lx.\n", (unsigned long)hr);
1308 err = AVERROR_UNKNOWN;
1309 }
1310
1311 IDirect3DDeviceManager9_CloseDeviceHandle(src_hwctx->devmgr,
1312 device_handle);
1313 }
1314 break;
1315 #endif
1316
1317 #if HAVE_OPENCL_D3D11
1318 case AV_HWDEVICE_TYPE_D3D11VA:
1319 {
1320 AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx;
1321 cl_context_properties props[5] = {
1322 CL_CONTEXT_PLATFORM,
1323 0,
1324 CL_CONTEXT_D3D11_DEVICE_KHR,
1325 (intptr_t)src_hwctx->device,
1326 0,
1327 };
1328 OpenCLDeviceSelector selector = {
1329 .platform_index = -1,
1330 .device_index = -1,
1331 .context = src_hwctx->device,
1332 .enumerate_platforms = &opencl_enumerate_platforms,
1333 .filter_platform = &opencl_filter_d3d11_platform,
1334 .enumerate_devices = &opencl_enumerate_d3d11_devices,
1335 .filter_device = &opencl_filter_gpu_device,
1336 };
1337
1338 err = opencl_device_create_internal(hwdev, &selector, props);
1339 }
1340 break;
1341 #endif
1342
1343 #if HAVE_OPENCL_DRM_ARM
1344 case AV_HWDEVICE_TYPE_DRM:
1345 {
1346 OpenCLDeviceSelector selector = {
1347 .platform_index = -1,
1348 .device_index = -1,
1349 .context = NULL,
1350 .enumerate_platforms = &opencl_enumerate_platforms,
1351 .filter_platform = &opencl_filter_drm_arm_platform,
1352 .enumerate_devices = &opencl_enumerate_devices,
1353 .filter_device = &opencl_filter_drm_arm_device,
1354 };
1355
1356 err = opencl_device_create_internal(hwdev, &selector, NULL);
1357 }
1358 break;
1359 #endif
1360
1361 default:
1362 err = AVERROR(ENOSYS);
1363 break;
1364 }
1365
1366 return err;
1367 }
1368
opencl_get_plane_format(enum AVPixelFormat pixfmt,int plane,int width,int height,cl_image_format * image_format,cl_image_desc * image_desc)1369 static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
1370 int plane, int width, int height,
1371 cl_image_format *image_format,
1372 cl_image_desc *image_desc)
1373 {
1374 const AVPixFmtDescriptor *desc;
1375 const AVComponentDescriptor *comp;
1376 int channels = 0, order = 0, depth = 0, step = 0;
1377 int wsub, hsub, alpha;
1378 int c;
1379
1380 if (plane >= AV_NUM_DATA_POINTERS)
1381 return AVERROR(ENOENT);
1382
1383 desc = av_pix_fmt_desc_get(pixfmt);
1384
1385 // Only normal images are allowed.
1386 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
1387 AV_PIX_FMT_FLAG_HWACCEL |
1388 AV_PIX_FMT_FLAG_PAL))
1389 return AVERROR(EINVAL);
1390
1391 wsub = 1 << desc->log2_chroma_w;
1392 hsub = 1 << desc->log2_chroma_h;
1393 // Subsampled components must be exact.
1394 if (width & wsub - 1 || height & hsub - 1)
1395 return AVERROR(EINVAL);
1396
1397 for (c = 0; c < desc->nb_components; c++) {
1398 comp = &desc->comp[c];
1399 if (comp->plane != plane)
1400 continue;
1401 // The step size must be a power of two.
1402 if (comp->step != 1 && comp->step != 2 &&
1403 comp->step != 4 && comp->step != 8)
1404 return AVERROR(EINVAL);
1405 // The bits in each component must be packed in the
1406 // most-significant-bits of the relevant bytes.
1407 if (comp->shift + comp->depth != 8 &&
1408 comp->shift + comp->depth != 16)
1409 return AVERROR(EINVAL);
1410 // The depth must not vary between components.
1411 if (depth && comp->depth != depth)
1412 return AVERROR(EINVAL);
1413 // If a single data element crosses multiple bytes then
1414 // it must match the native endianness.
1415 if (comp->depth > 8 &&
1416 HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
1417 return AVERROR(EINVAL);
1418 // A single data element must not contain multiple samples
1419 // from the same component.
1420 if (step && comp->step != step)
1421 return AVERROR(EINVAL);
1422
1423 depth = comp->depth;
1424 order = order * 10 + comp->offset / ((depth + 7) / 8) + 1;
1425 step = comp->step;
1426 alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
1427 c == desc->nb_components - 1);
1428 ++channels;
1429 }
1430 if (channels == 0)
1431 return AVERROR(ENOENT);
1432
1433 memset(image_format, 0, sizeof(*image_format));
1434 memset(image_desc, 0, sizeof(*image_desc));
1435 image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
1436
1437 if (plane == 0 || alpha) {
1438 image_desc->image_width = width;
1439 image_desc->image_height = height;
1440 image_desc->image_row_pitch = step * width;
1441 } else {
1442 image_desc->image_width = width / wsub;
1443 image_desc->image_height = height / hsub;
1444 image_desc->image_row_pitch = step * width / wsub;
1445 }
1446
1447 if (depth <= 8) {
1448 image_format->image_channel_data_type = CL_UNORM_INT8;
1449 } else {
1450 if (depth <= 16)
1451 image_format->image_channel_data_type = CL_UNORM_INT16;
1452 else
1453 return AVERROR(EINVAL);
1454 }
1455
1456 #define CHANNEL_ORDER(order, type) \
1457 case order: image_format->image_channel_order = type; break;
1458 switch (order) {
1459 CHANNEL_ORDER(1, CL_R);
1460 CHANNEL_ORDER(12, CL_RG);
1461 CHANNEL_ORDER(1234, CL_RGBA);
1462 CHANNEL_ORDER(2341, CL_ARGB);
1463 CHANNEL_ORDER(3214, CL_BGRA);
1464 #ifdef CL_ABGR
1465 CHANNEL_ORDER(4321, CL_ABGR);
1466 #endif
1467 default:
1468 return AVERROR(EINVAL);
1469 }
1470 #undef CHANNEL_ORDER
1471
1472 return 0;
1473 }
1474
opencl_frames_get_constraints(AVHWDeviceContext * hwdev,const void * hwconfig,AVHWFramesConstraints * constraints)1475 static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
1476 const void *hwconfig,
1477 AVHWFramesConstraints *constraints)
1478 {
1479 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
1480 cl_uint nb_image_formats;
1481 cl_image_format *image_formats = NULL;
1482 cl_int cle;
1483 enum AVPixelFormat pix_fmt;
1484 int err, pix_fmts_found;
1485 size_t max_width, max_height;
1486
1487 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
1488 sizeof(max_width), &max_width, NULL);
1489 if (cle != CL_SUCCESS) {
1490 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1491 "supported image width: %d.\n", cle);
1492 } else {
1493 constraints->max_width = max_width;
1494 }
1495 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
1496 sizeof(max_height), &max_height, NULL);
1497 if (cle != CL_SUCCESS) {
1498 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1499 "supported image height: %d.\n", cle);
1500 } else {
1501 constraints->max_height = max_height;
1502 }
1503 av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
1504 constraints->max_width, constraints->max_height);
1505
1506 cle = clGetSupportedImageFormats(hwctx->context,
1507 CL_MEM_READ_WRITE,
1508 CL_MEM_OBJECT_IMAGE2D,
1509 0, NULL, &nb_image_formats);
1510 if (cle != CL_SUCCESS) {
1511 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1512 "image formats: %d.\n", cle);
1513 err = AVERROR(ENOSYS);
1514 goto fail;
1515 }
1516 if (nb_image_formats == 0) {
1517 av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
1518 "driver (zero supported image formats).\n");
1519 err = AVERROR(ENOSYS);
1520 goto fail;
1521 }
1522
1523 image_formats =
1524 av_malloc_array(nb_image_formats, sizeof(*image_formats));
1525 if (!image_formats) {
1526 err = AVERROR(ENOMEM);
1527 goto fail;
1528 }
1529
1530 cle = clGetSupportedImageFormats(hwctx->context,
1531 CL_MEM_READ_WRITE,
1532 CL_MEM_OBJECT_IMAGE2D,
1533 nb_image_formats,
1534 image_formats, NULL);
1535 if (cle != CL_SUCCESS) {
1536 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1537 "image formats: %d.\n", cle);
1538 err = AVERROR(ENOSYS);
1539 goto fail;
1540 }
1541
1542 pix_fmts_found = 0;
1543 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
1544 cl_image_format image_format;
1545 cl_image_desc image_desc;
1546 int plane, i;
1547
1548 for (plane = 0;; plane++) {
1549 err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
1550 &image_format,
1551 &image_desc);
1552 if (err < 0)
1553 break;
1554
1555 for (i = 0; i < nb_image_formats; i++) {
1556 if (image_formats[i].image_channel_order ==
1557 image_format.image_channel_order &&
1558 image_formats[i].image_channel_data_type ==
1559 image_format.image_channel_data_type)
1560 break;
1561 }
1562 if (i == nb_image_formats) {
1563 err = AVERROR(EINVAL);
1564 break;
1565 }
1566 }
1567 if (err != AVERROR(ENOENT))
1568 continue;
1569
1570 av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
1571 av_get_pix_fmt_name(pix_fmt));
1572
1573 err = av_reallocp_array(&constraints->valid_sw_formats,
1574 pix_fmts_found + 2,
1575 sizeof(*constraints->valid_sw_formats));
1576 if (err < 0)
1577 goto fail;
1578 constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
1579 constraints->valid_sw_formats[pix_fmts_found + 1] =
1580 AV_PIX_FMT_NONE;
1581 ++pix_fmts_found;
1582 }
1583
1584 av_freep(&image_formats);
1585
1586 constraints->valid_hw_formats =
1587 av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
1588 if (!constraints->valid_hw_formats) {
1589 err = AVERROR(ENOMEM);
1590 goto fail;
1591 }
1592 constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
1593 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1594
1595 return 0;
1596
1597 fail:
1598 av_freep(&image_formats);
1599 return err;
1600 }
1601
opencl_pool_free(void * opaque,uint8_t * data)1602 static void opencl_pool_free(void *opaque, uint8_t *data)
1603 {
1604 AVHWFramesContext *hwfc = opaque;
1605 AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
1606 cl_int cle;
1607 int p;
1608
1609 for (p = 0; p < desc->nb_planes; p++) {
1610 cle = clReleaseMemObject(desc->planes[p]);
1611 if (cle != CL_SUCCESS) {
1612 av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
1613 "%d.\n", p, cle);
1614 }
1615 }
1616
1617 av_free(desc);
1618 }
1619
opencl_pool_alloc(void * opaque,buffer_size_t size)1620 static AVBufferRef *opencl_pool_alloc(void *opaque, buffer_size_t size)
1621 {
1622 AVHWFramesContext *hwfc = opaque;
1623 AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1624 AVOpenCLFrameDescriptor *desc;
1625 cl_int cle;
1626 cl_mem image;
1627 cl_image_format image_format;
1628 cl_image_desc image_desc;
1629 int err, p;
1630 AVBufferRef *ref;
1631
1632 desc = av_mallocz(sizeof(*desc));
1633 if (!desc)
1634 return NULL;
1635
1636 for (p = 0;; p++) {
1637 err = opencl_get_plane_format(hwfc->sw_format, p,
1638 hwfc->width, hwfc->height,
1639 &image_format, &image_desc);
1640 if (err == AVERROR(ENOENT))
1641 break;
1642 if (err < 0)
1643 goto fail;
1644
1645 // For generic image objects, the pitch is determined by the
1646 // implementation.
1647 image_desc.image_row_pitch = 0;
1648
1649 image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
1650 &image_format, &image_desc, NULL, &cle);
1651 if (!image) {
1652 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
1653 "plane %d: %d.\n", p, cle);
1654 goto fail;
1655 }
1656
1657 desc->planes[p] = image;
1658 }
1659
1660 desc->nb_planes = p;
1661
1662 ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
1663 &opencl_pool_free, hwfc, 0);
1664 if (!ref)
1665 goto fail;
1666
1667 return ref;
1668
1669 fail:
1670 for (p = 0; desc->planes[p]; p++)
1671 clReleaseMemObject(desc->planes[p]);
1672 av_free(desc);
1673 return NULL;
1674 }
1675
opencl_frames_init_command_queue(AVHWFramesContext * hwfc)1676 static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
1677 {
1678 AVOpenCLFramesContext *hwctx = hwfc->hwctx;
1679 OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
1680 OpenCLFramesContext *priv = hwfc->internal->priv;
1681 cl_int cle;
1682
1683 priv->command_queue = hwctx->command_queue ? hwctx->command_queue
1684 : devpriv->command_queue;
1685 cle = clRetainCommandQueue(priv->command_queue);
1686 if (cle != CL_SUCCESS) {
1687 av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
1688 "command queue: %d.\n", cle);
1689 return AVERROR(EIO);
1690 }
1691
1692 return 0;
1693 }
1694
opencl_frames_init(AVHWFramesContext * hwfc)1695 static int opencl_frames_init(AVHWFramesContext *hwfc)
1696 {
1697 if (!hwfc->pool) {
1698 hwfc->internal->pool_internal =
1699 av_buffer_pool_init2(sizeof(cl_mem), hwfc,
1700 &opencl_pool_alloc, NULL);
1701 if (!hwfc->internal->pool_internal)
1702 return AVERROR(ENOMEM);
1703 }
1704
1705 return opencl_frames_init_command_queue(hwfc);
1706 }
1707
opencl_frames_uninit(AVHWFramesContext * hwfc)1708 static void opencl_frames_uninit(AVHWFramesContext *hwfc)
1709 {
1710 OpenCLFramesContext *priv = hwfc->internal->priv;
1711 cl_int cle;
1712
1713 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
1714 int i, p;
1715 for (i = 0; i < priv->nb_mapped_frames; i++) {
1716 AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i];
1717 for (p = 0; p < desc->nb_planes; p++) {
1718 cle = clReleaseMemObject(desc->planes[p]);
1719 if (cle != CL_SUCCESS) {
1720 av_log(hwfc, AV_LOG_ERROR, "Failed to release mapped "
1721 "frame object (frame %d plane %d): %d.\n",
1722 i, p, cle);
1723 }
1724 }
1725 }
1726 av_freep(&priv->mapped_frames);
1727 #endif
1728
1729 if (priv->command_queue) {
1730 cle = clReleaseCommandQueue(priv->command_queue);
1731 if (cle != CL_SUCCESS) {
1732 av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
1733 "command queue: %d.\n", cle);
1734 }
1735 priv->command_queue = NULL;
1736 }
1737 }
1738
opencl_get_buffer(AVHWFramesContext * hwfc,AVFrame * frame)1739 static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
1740 {
1741 AVOpenCLFrameDescriptor *desc;
1742 int p;
1743
1744 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1745 if (!frame->buf[0])
1746 return AVERROR(ENOMEM);
1747
1748 desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
1749
1750 for (p = 0; p < desc->nb_planes; p++)
1751 frame->data[p] = (uint8_t*)desc->planes[p];
1752
1753 frame->format = AV_PIX_FMT_OPENCL;
1754 frame->width = hwfc->width;
1755 frame->height = hwfc->height;
1756
1757 return 0;
1758 }
1759
opencl_transfer_get_formats(AVHWFramesContext * hwfc,enum AVHWFrameTransferDirection dir,enum AVPixelFormat ** formats)1760 static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
1761 enum AVHWFrameTransferDirection dir,
1762 enum AVPixelFormat **formats)
1763 {
1764 enum AVPixelFormat *fmts;
1765
1766 fmts = av_malloc_array(2, sizeof(*fmts));
1767 if (!fmts)
1768 return AVERROR(ENOMEM);
1769
1770 fmts[0] = hwfc->sw_format;
1771 fmts[1] = AV_PIX_FMT_NONE;
1772
1773 *formats = fmts;
1774 return 0;
1775 }
1776
opencl_wait_events(AVHWFramesContext * hwfc,cl_event * events,int nb_events)1777 static int opencl_wait_events(AVHWFramesContext *hwfc,
1778 cl_event *events, int nb_events)
1779 {
1780 cl_int cle;
1781 int i;
1782
1783 cle = clWaitForEvents(nb_events, events);
1784 if (cle != CL_SUCCESS) {
1785 av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
1786 "completion: %d.\n", cle);
1787 return AVERROR(EIO);
1788 }
1789
1790 for (i = 0; i < nb_events; i++) {
1791 cle = clReleaseEvent(events[i]);
1792 if (cle != CL_SUCCESS) {
1793 av_log(hwfc, AV_LOG_ERROR, "Failed to release "
1794 "event: %d.\n", cle);
1795 }
1796 }
1797
1798 return 0;
1799 }
1800
opencl_transfer_data_from(AVHWFramesContext * hwfc,AVFrame * dst,const AVFrame * src)1801 static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
1802 AVFrame *dst, const AVFrame *src)
1803 {
1804 OpenCLFramesContext *priv = hwfc->internal->priv;
1805 cl_image_format image_format;
1806 cl_image_desc image_desc;
1807 cl_int cle;
1808 size_t origin[3] = { 0, 0, 0 };
1809 size_t region[3];
1810 cl_event events[AV_NUM_DATA_POINTERS];
1811 int err, p;
1812
1813 if (dst->format != hwfc->sw_format)
1814 return AVERROR(EINVAL);
1815
1816 for (p = 0;; p++) {
1817 err = opencl_get_plane_format(hwfc->sw_format, p,
1818 src->width, src->height,
1819 &image_format, &image_desc);
1820 if (err < 0) {
1821 if (err == AVERROR(ENOENT))
1822 err = 0;
1823 break;
1824 }
1825
1826 if (!dst->data[p]) {
1827 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1828 "destination frame for transfer.\n", p);
1829 err = AVERROR(EINVAL);
1830 break;
1831 }
1832
1833 region[0] = image_desc.image_width;
1834 region[1] = image_desc.image_height;
1835 region[2] = 1;
1836
1837 cle = clEnqueueReadImage(priv->command_queue,
1838 (cl_mem)src->data[p],
1839 CL_FALSE, origin, region,
1840 dst->linesize[p], 0,
1841 dst->data[p],
1842 0, NULL, &events[p]);
1843 if (cle != CL_SUCCESS) {
1844 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
1845 "OpenCL image plane %d: %d.\n", p, cle);
1846 err = AVERROR(EIO);
1847 break;
1848 }
1849 }
1850
1851 opencl_wait_events(hwfc, events, p);
1852
1853 return err;
1854 }
1855
opencl_transfer_data_to(AVHWFramesContext * hwfc,AVFrame * dst,const AVFrame * src)1856 static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
1857 AVFrame *dst, const AVFrame *src)
1858 {
1859 OpenCLFramesContext *priv = hwfc->internal->priv;
1860 cl_image_format image_format;
1861 cl_image_desc image_desc;
1862 cl_int cle;
1863 size_t origin[3] = { 0, 0, 0 };
1864 size_t region[3];
1865 cl_event events[AV_NUM_DATA_POINTERS];
1866 int err, p;
1867
1868 if (src->format != hwfc->sw_format)
1869 return AVERROR(EINVAL);
1870
1871 for (p = 0;; p++) {
1872 err = opencl_get_plane_format(hwfc->sw_format, p,
1873 src->width, src->height,
1874 &image_format, &image_desc);
1875 if (err < 0) {
1876 if (err == AVERROR(ENOENT))
1877 err = 0;
1878 break;
1879 }
1880
1881 if (!src->data[p]) {
1882 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1883 "source frame for transfer.\n", p);
1884 err = AVERROR(EINVAL);
1885 break;
1886 }
1887
1888 region[0] = image_desc.image_width;
1889 region[1] = image_desc.image_height;
1890 region[2] = 1;
1891
1892 cle = clEnqueueWriteImage(priv->command_queue,
1893 (cl_mem)dst->data[p],
1894 CL_FALSE, origin, region,
1895 src->linesize[p], 0,
1896 src->data[p],
1897 0, NULL, &events[p]);
1898 if (cle != CL_SUCCESS) {
1899 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
1900 "OpenCL image plane %d: %d.\n", p, cle);
1901 err = AVERROR(EIO);
1902 break;
1903 }
1904 }
1905
1906 opencl_wait_events(hwfc, events, p);
1907
1908 return err;
1909 }
1910
1911 typedef struct OpenCLMapping {
1912 // The mapped addresses for each plane.
1913 // The destination frame is not available when we unmap, so these
1914 // need to be stored separately.
1915 void *address[AV_NUM_DATA_POINTERS];
1916 } OpenCLMapping;
1917
opencl_unmap_frame(AVHWFramesContext * hwfc,HWMapDescriptor * hwmap)1918 static void opencl_unmap_frame(AVHWFramesContext *hwfc,
1919 HWMapDescriptor *hwmap)
1920 {
1921 OpenCLFramesContext *priv = hwfc->internal->priv;
1922 OpenCLMapping *map = hwmap->priv;
1923 cl_event events[AV_NUM_DATA_POINTERS];
1924 int p, e;
1925 cl_int cle;
1926
1927 for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
1928 if (!map->address[p])
1929 break;
1930
1931 cle = clEnqueueUnmapMemObject(priv->command_queue,
1932 (cl_mem)hwmap->source->data[p],
1933 map->address[p],
1934 0, NULL, &events[e]);
1935 if (cle != CL_SUCCESS) {
1936 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
1937 "image plane %d: %d.\n", p, cle);
1938 }
1939 ++e;
1940 }
1941
1942 opencl_wait_events(hwfc, events, e);
1943
1944 av_free(map);
1945 }
1946
opencl_map_frame(AVHWFramesContext * hwfc,AVFrame * dst,const AVFrame * src,int flags)1947 static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
1948 const AVFrame *src, int flags)
1949 {
1950 OpenCLFramesContext *priv = hwfc->internal->priv;
1951 cl_map_flags map_flags;
1952 cl_image_format image_format;
1953 cl_image_desc image_desc;
1954 cl_int cle;
1955 OpenCLMapping *map;
1956 size_t origin[3] = { 0, 0, 0 };
1957 size_t region[3];
1958 size_t row_pitch;
1959 cl_event events[AV_NUM_DATA_POINTERS];
1960 int err, p;
1961
1962 av_assert0(hwfc->sw_format == dst->format);
1963
1964 if (flags & AV_HWFRAME_MAP_OVERWRITE &&
1965 !(flags & AV_HWFRAME_MAP_READ)) {
1966 // This is mutually exclusive with the read/write flags, so
1967 // there is no way to map with read here.
1968 map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
1969 } else {
1970 map_flags = 0;
1971 if (flags & AV_HWFRAME_MAP_READ)
1972 map_flags |= CL_MAP_READ;
1973 if (flags & AV_HWFRAME_MAP_WRITE)
1974 map_flags |= CL_MAP_WRITE;
1975 }
1976
1977 map = av_mallocz(sizeof(*map));
1978 if (!map)
1979 return AVERROR(ENOMEM);
1980
1981 for (p = 0;; p++) {
1982 err = opencl_get_plane_format(hwfc->sw_format, p,
1983 src->width, src->height,
1984 &image_format, &image_desc);
1985 if (err == AVERROR(ENOENT))
1986 break;
1987 if (err < 0)
1988 goto fail;
1989
1990 region[0] = image_desc.image_width;
1991 region[1] = image_desc.image_height;
1992 region[2] = 1;
1993
1994 map->address[p] =
1995 clEnqueueMapImage(priv->command_queue,
1996 (cl_mem)src->data[p],
1997 CL_FALSE, map_flags, origin, region,
1998 &row_pitch, NULL, 0, NULL,
1999 &events[p], &cle);
2000 if (!map->address[p]) {
2001 av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
2002 "image plane %d: %d.\n", p, cle);
2003 err = AVERROR(EIO);
2004 goto fail;
2005 }
2006
2007 dst->data[p] = map->address[p];
2008
2009 av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
2010 p, src->data[p], dst->data[p]);
2011 }
2012
2013 err = opencl_wait_events(hwfc, events, p);
2014 if (err < 0)
2015 goto fail;
2016
2017 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
2018 &opencl_unmap_frame, map);
2019 if (err < 0)
2020 goto fail;
2021
2022 dst->width = src->width;
2023 dst->height = src->height;
2024
2025 return 0;
2026
2027 fail:
2028 for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
2029 if (!map->address[p])
2030 break;
2031 clEnqueueUnmapMemObject(priv->command_queue,
2032 (cl_mem)src->data[p],
2033 map->address[p],
2034 0, NULL, &events[p]);
2035 }
2036 if (p > 0)
2037 opencl_wait_events(hwfc, events, p);
2038 av_freep(&map);
2039 return err;
2040 }
2041
2042 #if HAVE_OPENCL_DRM_BEIGNET
2043
2044 typedef struct DRMBeignetToOpenCLMapping {
2045 AVFrame *drm_frame;
2046 AVDRMFrameDescriptor *drm_desc;
2047
2048 AVOpenCLFrameDescriptor frame;
2049 } DRMBeignetToOpenCLMapping;
2050
opencl_unmap_from_drm_beignet(AVHWFramesContext * dst_fc,HWMapDescriptor * hwmap)2051 static void opencl_unmap_from_drm_beignet(AVHWFramesContext *dst_fc,
2052 HWMapDescriptor *hwmap)
2053 {
2054 DRMBeignetToOpenCLMapping *mapping = hwmap->priv;
2055 cl_int cle;
2056 int i;
2057
2058 for (i = 0; i < mapping->frame.nb_planes; i++) {
2059 cle = clReleaseMemObject(mapping->frame.planes[i]);
2060 if (cle != CL_SUCCESS) {
2061 av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL image "
2062 "of plane %d of DRM frame: %d.\n", i, cle);
2063 }
2064 }
2065
2066 av_free(mapping);
2067 }
2068
opencl_map_from_drm_beignet(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2069 static int opencl_map_from_drm_beignet(AVHWFramesContext *dst_fc,
2070 AVFrame *dst, const AVFrame *src,
2071 int flags)
2072 {
2073 AVOpenCLDeviceContext *hwctx = dst_fc->device_ctx->hwctx;
2074 OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
2075 DRMBeignetToOpenCLMapping *mapping;
2076 const AVDRMFrameDescriptor *desc;
2077 cl_int cle;
2078 int err, i, j, p;
2079
2080 desc = (const AVDRMFrameDescriptor*)src->data[0];
2081
2082 mapping = av_mallocz(sizeof(*mapping));
2083 if (!mapping)
2084 return AVERROR(ENOMEM);
2085
2086 p = 0;
2087 for (i = 0; i < desc->nb_layers; i++) {
2088 const AVDRMLayerDescriptor *layer = &desc->layers[i];
2089 for (j = 0; j < layer->nb_planes; j++) {
2090 const AVDRMPlaneDescriptor *plane = &layer->planes[j];
2091 const AVDRMObjectDescriptor *object =
2092 &desc->objects[plane->object_index];
2093
2094 cl_import_image_info_intel image_info = {
2095 .fd = object->fd,
2096 .size = object->size,
2097 .type = CL_MEM_OBJECT_IMAGE2D,
2098 .offset = plane->offset,
2099 .row_pitch = plane->pitch,
2100 };
2101 cl_image_desc image_desc;
2102
2103 err = opencl_get_plane_format(dst_fc->sw_format, p,
2104 src->width, src->height,
2105 &image_info.fmt,
2106 &image_desc);
2107 if (err < 0) {
2108 av_log(dst_fc, AV_LOG_ERROR, "DRM frame layer %d "
2109 "plane %d is not representable in OpenCL: %d.\n",
2110 i, j, err);
2111 goto fail;
2112 }
2113 image_info.width = image_desc.image_width;
2114 image_info.height = image_desc.image_height;
2115
2116 mapping->frame.planes[p] =
2117 priv->clCreateImageFromFdINTEL(hwctx->context,
2118 &image_info, &cle);
2119 if (!mapping->frame.planes[p]) {
2120 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
2121 "from layer %d plane %d of DRM frame: %d.\n",
2122 i, j, cle);
2123 err = AVERROR(EIO);
2124 goto fail;
2125 }
2126
2127 dst->data[p] = (uint8_t*)mapping->frame.planes[p];
2128 mapping->frame.nb_planes = ++p;
2129 }
2130 }
2131
2132 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2133 &opencl_unmap_from_drm_beignet,
2134 mapping);
2135 if (err < 0)
2136 goto fail;
2137
2138 dst->width = src->width;
2139 dst->height = src->height;
2140
2141 return 0;
2142
2143 fail:
2144 for (p = 0; p < mapping->frame.nb_planes; p++) {
2145 if (mapping->frame.planes[p])
2146 clReleaseMemObject(mapping->frame.planes[p]);
2147 }
2148 av_free(mapping);
2149 return err;
2150 }
2151
2152 #if HAVE_OPENCL_VAAPI_BEIGNET
2153
opencl_map_from_vaapi(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2154 static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc,
2155 AVFrame *dst, const AVFrame *src,
2156 int flags)
2157 {
2158 AVFrame *tmp;
2159 int err;
2160
2161 tmp = av_frame_alloc();
2162 if (!tmp)
2163 return AVERROR(ENOMEM);
2164
2165 tmp->format = AV_PIX_FMT_DRM_PRIME;
2166
2167 err = av_hwframe_map(tmp, src, flags);
2168 if (err < 0)
2169 goto fail;
2170
2171 err = opencl_map_from_drm_beignet(dst_fc, dst, tmp, flags);
2172 if (err < 0)
2173 goto fail;
2174
2175 err = ff_hwframe_map_replace(dst, src);
2176
2177 fail:
2178 av_frame_free(&tmp);
2179 return err;
2180 }
2181
2182 #endif /* HAVE_OPENCL_VAAPI_BEIGNET */
2183 #endif /* HAVE_OPENCL_DRM_BEIGNET */
2184
opencl_mem_flags_for_mapping(int map_flags)2185 static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
2186 {
2187 if ((map_flags & AV_HWFRAME_MAP_READ) &&
2188 (map_flags & AV_HWFRAME_MAP_WRITE))
2189 return CL_MEM_READ_WRITE;
2190 else if (map_flags & AV_HWFRAME_MAP_READ)
2191 return CL_MEM_READ_ONLY;
2192 else if (map_flags & AV_HWFRAME_MAP_WRITE)
2193 return CL_MEM_WRITE_ONLY;
2194 else
2195 return 0;
2196 }
2197
2198 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2199
opencl_unmap_from_qsv(AVHWFramesContext * dst_fc,HWMapDescriptor * hwmap)2200 static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
2201 HWMapDescriptor *hwmap)
2202 {
2203 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2204 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2205 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2206 cl_event event;
2207 cl_int cle;
2208 int p;
2209
2210 av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
2211
2212 cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
2213 frames_priv->command_queue, desc->nb_planes, desc->planes,
2214 0, NULL, &event);
2215 if (cle != CL_SUCCESS) {
2216 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2217 "handles: %d.\n", cle);
2218 }
2219
2220 opencl_wait_events(dst_fc, &event, 1);
2221
2222 for (p = 0; p < desc->nb_planes; p++) {
2223 cle = clReleaseMemObject(desc->planes[p]);
2224 if (cle != CL_SUCCESS) {
2225 av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
2226 "image of plane %d of QSV/VAAPI surface: %d\n",
2227 p, cle);
2228 }
2229 }
2230
2231 av_free(desc);
2232 }
2233
opencl_map_from_qsv(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2234 static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
2235 const AVFrame *src, int flags)
2236 {
2237 AVHWFramesContext *src_fc =
2238 (AVHWFramesContext*)src->hw_frames_ctx->data;
2239 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2240 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2241 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2242 AVOpenCLFrameDescriptor *desc;
2243 VASurfaceID va_surface;
2244 cl_mem_flags cl_flags;
2245 cl_event event;
2246 cl_int cle;
2247 int err, p;
2248
2249 #if CONFIG_LIBMFX
2250 if (src->format == AV_PIX_FMT_QSV) {
2251 mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
2252 va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
2253 } else
2254 #endif
2255 if (src->format == AV_PIX_FMT_VAAPI) {
2256 va_surface = (VASurfaceID)(uintptr_t)src->data[3];
2257 } else {
2258 return AVERROR(ENOSYS);
2259 }
2260
2261 cl_flags = opencl_mem_flags_for_mapping(flags);
2262 if (!cl_flags)
2263 return AVERROR(EINVAL);
2264
2265 av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
2266 "OpenCL.\n", va_surface);
2267
2268 desc = av_mallocz(sizeof(*desc));
2269 if (!desc)
2270 return AVERROR(ENOMEM);
2271
2272 // The cl_intel_va_api_media_sharing extension only supports NV12
2273 // surfaces, so for now there are always exactly two planes.
2274 desc->nb_planes = 2;
2275
2276 for (p = 0; p < desc->nb_planes; p++) {
2277 desc->planes[p] =
2278 device_priv->clCreateFromVA_APIMediaSurfaceINTEL(
2279 dst_dev->context, cl_flags, &va_surface, p, &cle);
2280 if (!desc->planes[p]) {
2281 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2282 "image from plane %d of QSV/VAAPI surface "
2283 "%#x: %d.\n", p, va_surface, cle);
2284 err = AVERROR(EIO);
2285 goto fail;
2286 }
2287
2288 dst->data[p] = (uint8_t*)desc->planes[p];
2289 }
2290
2291 cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
2292 frames_priv->command_queue, desc->nb_planes, desc->planes,
2293 0, NULL, &event);
2294 if (cle != CL_SUCCESS) {
2295 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2296 "handles: %d.\n", cle);
2297 err = AVERROR(EIO);
2298 goto fail;
2299 }
2300
2301 err = opencl_wait_events(dst_fc, &event, 1);
2302 if (err < 0)
2303 goto fail;
2304
2305 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2306 &opencl_unmap_from_qsv, desc);
2307 if (err < 0)
2308 goto fail;
2309
2310 dst->width = src->width;
2311 dst->height = src->height;
2312
2313 return 0;
2314
2315 fail:
2316 for (p = 0; p < desc->nb_planes; p++)
2317 if (desc->planes[p])
2318 clReleaseMemObject(desc->planes[p]);
2319 av_freep(&desc);
2320 return err;
2321 }
2322
2323 #endif
2324
2325 #if HAVE_OPENCL_DXVA2
2326
opencl_unmap_from_dxva2(AVHWFramesContext * dst_fc,HWMapDescriptor * hwmap)2327 static void opencl_unmap_from_dxva2(AVHWFramesContext *dst_fc,
2328 HWMapDescriptor *hwmap)
2329 {
2330 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2331 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2332 OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
2333 cl_event event;
2334 cl_int cle;
2335
2336 av_log(dst_fc, AV_LOG_DEBUG, "Unmap DXVA2 surface from OpenCL.\n");
2337
2338 cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
2339 frames_priv->command_queue, desc->nb_planes, desc->planes,
2340 0, NULL, &event);
2341 if (cle != CL_SUCCESS) {
2342 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2343 "handle: %d.\n", cle);
2344 return;
2345 }
2346
2347 opencl_wait_events(dst_fc, &event, 1);
2348 }
2349
opencl_map_from_dxva2(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2350 static int opencl_map_from_dxva2(AVHWFramesContext *dst_fc, AVFrame *dst,
2351 const AVFrame *src, int flags)
2352 {
2353 AVHWFramesContext *src_fc =
2354 (AVHWFramesContext*)src->hw_frames_ctx->data;
2355 AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
2356 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2357 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2358 AVOpenCLFrameDescriptor *desc;
2359 cl_event event;
2360 cl_int cle;
2361 int err, i;
2362
2363 av_log(dst_fc, AV_LOG_DEBUG, "Map DXVA2 surface %p to "
2364 "OpenCL.\n", src->data[3]);
2365
2366 for (i = 0; i < src_hwctx->nb_surfaces; i++) {
2367 if (src_hwctx->surfaces[i] == (IDirect3DSurface9*)src->data[3])
2368 break;
2369 }
2370 if (i >= src_hwctx->nb_surfaces) {
2371 av_log(dst_fc, AV_LOG_ERROR, "Trying to map from a surface which "
2372 "is not in the mapped frames context.\n");
2373 return AVERROR(EINVAL);
2374 }
2375
2376 desc = &frames_priv->mapped_frames[i];
2377
2378 cle = device_priv->clEnqueueAcquireDX9MediaSurfacesKHR(
2379 frames_priv->command_queue, desc->nb_planes, desc->planes,
2380 0, NULL, &event);
2381 if (cle != CL_SUCCESS) {
2382 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2383 "handle: %d.\n", cle);
2384 return AVERROR(EIO);
2385 }
2386
2387 err = opencl_wait_events(dst_fc, &event, 1);
2388 if (err < 0)
2389 goto fail;
2390
2391 for (i = 0; i < desc->nb_planes; i++)
2392 dst->data[i] = (uint8_t*)desc->planes[i];
2393
2394 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2395 &opencl_unmap_from_dxva2, desc);
2396 if (err < 0)
2397 goto fail;
2398
2399 dst->width = src->width;
2400 dst->height = src->height;
2401
2402 return 0;
2403
2404 fail:
2405 cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
2406 frames_priv->command_queue, desc->nb_planes, desc->planes,
2407 0, NULL, &event);
2408 if (cle == CL_SUCCESS)
2409 opencl_wait_events(dst_fc, &event, 1);
2410 return err;
2411 }
2412
opencl_frames_derive_from_dxva2(AVHWFramesContext * dst_fc,AVHWFramesContext * src_fc,int flags)2413 static int opencl_frames_derive_from_dxva2(AVHWFramesContext *dst_fc,
2414 AVHWFramesContext *src_fc, int flags)
2415 {
2416 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2417 AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
2418 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2419 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2420 cl_mem_flags cl_flags;
2421 cl_int cle;
2422 int err, i, p, nb_planes;
2423
2424 if (src_fc->sw_format != AV_PIX_FMT_NV12) {
2425 av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
2426 "for DXVA2 to OpenCL mapping.\n");
2427 return AVERROR(EINVAL);
2428 }
2429 nb_planes = 2;
2430
2431 if (src_fc->initial_pool_size == 0) {
2432 av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
2433 "for DXVA2 to OpenCL mapping.\n");
2434 return AVERROR(EINVAL);
2435 }
2436
2437 cl_flags = opencl_mem_flags_for_mapping(flags);
2438 if (!cl_flags)
2439 return AVERROR(EINVAL);
2440
2441 frames_priv->nb_mapped_frames = src_hwctx->nb_surfaces;
2442
2443 frames_priv->mapped_frames =
2444 av_mallocz_array(frames_priv->nb_mapped_frames,
2445 sizeof(*frames_priv->mapped_frames));
2446 if (!frames_priv->mapped_frames)
2447 return AVERROR(ENOMEM);
2448
2449 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2450 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2451 cl_dx9_surface_info_khr surface_info = {
2452 .resource = src_hwctx->surfaces[i],
2453 .shared_handle = NULL,
2454 };
2455 desc->nb_planes = nb_planes;
2456 for (p = 0; p < nb_planes; p++) {
2457 desc->planes[p] =
2458 device_priv->clCreateFromDX9MediaSurfaceKHR(
2459 dst_dev->context, cl_flags,
2460 device_priv->dx9_media_adapter_type,
2461 &surface_info, p, &cle);
2462 if (!desc->planes[p]) {
2463 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2464 "image from plane %d of DXVA2 surface %d: %d.\n",
2465 p, i, cle);
2466 err = AVERROR(EIO);
2467 goto fail;
2468 }
2469 }
2470 }
2471
2472 return 0;
2473
2474 fail:
2475 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2476 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2477 for (p = 0; p < desc->nb_planes; p++) {
2478 if (desc->planes[p])
2479 clReleaseMemObject(desc->planes[p]);
2480 }
2481 }
2482 av_freep(&frames_priv->mapped_frames);
2483 frames_priv->nb_mapped_frames = 0;
2484 return err;
2485 }
2486
2487 #endif
2488
2489 #if HAVE_OPENCL_D3D11
2490
opencl_unmap_from_d3d11(AVHWFramesContext * dst_fc,HWMapDescriptor * hwmap)2491 static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc,
2492 HWMapDescriptor *hwmap)
2493 {
2494 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2495 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2496 OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
2497 cl_event event;
2498 cl_int cle;
2499
2500 cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2501 frames_priv->command_queue, desc->nb_planes, desc->planes,
2502 0, NULL, &event);
2503 if (cle != CL_SUCCESS) {
2504 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2505 "handle: %d.\n", cle);
2506 }
2507
2508 opencl_wait_events(dst_fc, &event, 1);
2509 }
2510
opencl_map_from_d3d11(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2511 static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst,
2512 const AVFrame *src, int flags)
2513 {
2514 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2515 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2516 AVOpenCLFrameDescriptor *desc;
2517 cl_event event;
2518 cl_int cle;
2519 int err, index, i;
2520
2521 index = (intptr_t)src->data[1];
2522 if (index >= frames_priv->nb_mapped_frames) {
2523 av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for "
2524 "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames);
2525 return AVERROR(EINVAL);
2526 }
2527
2528 av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n",
2529 index);
2530
2531 desc = &frames_priv->mapped_frames[index];
2532
2533 cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR(
2534 frames_priv->command_queue, desc->nb_planes, desc->planes,
2535 0, NULL, &event);
2536 if (cle != CL_SUCCESS) {
2537 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2538 "handle: %d.\n", cle);
2539 return AVERROR(EIO);
2540 }
2541
2542 err = opencl_wait_events(dst_fc, &event, 1);
2543 if (err < 0)
2544 goto fail;
2545
2546 for (i = 0; i < desc->nb_planes; i++)
2547 dst->data[i] = (uint8_t*)desc->planes[i];
2548
2549 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2550 &opencl_unmap_from_d3d11, desc);
2551 if (err < 0)
2552 goto fail;
2553
2554 dst->width = src->width;
2555 dst->height = src->height;
2556
2557 return 0;
2558
2559 fail:
2560 cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2561 frames_priv->command_queue, desc->nb_planes, desc->planes,
2562 0, NULL, &event);
2563 if (cle == CL_SUCCESS)
2564 opencl_wait_events(dst_fc, &event, 1);
2565 return err;
2566 }
2567
opencl_frames_derive_from_d3d11(AVHWFramesContext * dst_fc,AVHWFramesContext * src_fc,int flags)2568 static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc,
2569 AVHWFramesContext *src_fc, int flags)
2570 {
2571 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2572 AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx;
2573 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2574 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2575 cl_mem_flags cl_flags;
2576 cl_int cle;
2577 int err, i, p, nb_planes;
2578
2579 if (src_fc->sw_format != AV_PIX_FMT_NV12) {
2580 av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
2581 "for D3D11 to OpenCL mapping.\n");
2582 return AVERROR(EINVAL);
2583 }
2584 nb_planes = 2;
2585
2586 if (src_fc->initial_pool_size == 0) {
2587 av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
2588 "for D3D11 to OpenCL mapping.\n");
2589 return AVERROR(EINVAL);
2590 }
2591
2592 cl_flags = opencl_mem_flags_for_mapping(flags);
2593 if (!cl_flags)
2594 return AVERROR(EINVAL);
2595
2596 frames_priv->nb_mapped_frames = src_fc->initial_pool_size;
2597
2598 frames_priv->mapped_frames =
2599 av_mallocz_array(frames_priv->nb_mapped_frames,
2600 sizeof(*frames_priv->mapped_frames));
2601 if (!frames_priv->mapped_frames)
2602 return AVERROR(ENOMEM);
2603
2604 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2605 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2606 desc->nb_planes = nb_planes;
2607 for (p = 0; p < nb_planes; p++) {
2608 UINT subresource = 2 * i + p;
2609
2610 desc->planes[p] =
2611 device_priv->clCreateFromD3D11Texture2DKHR(
2612 dst_dev->context, cl_flags, src_hwctx->texture,
2613 subresource, &cle);
2614 if (!desc->planes[p]) {
2615 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2616 "image from plane %d of D3D texture "
2617 "index %d (subresource %u): %d.\n",
2618 p, i, (unsigned int)subresource, cle);
2619 err = AVERROR(EIO);
2620 goto fail;
2621 }
2622 }
2623 }
2624
2625 return 0;
2626
2627 fail:
2628 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2629 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2630 for (p = 0; p < desc->nb_planes; p++) {
2631 if (desc->planes[p])
2632 clReleaseMemObject(desc->planes[p]);
2633 }
2634 }
2635 av_freep(&frames_priv->mapped_frames);
2636 frames_priv->nb_mapped_frames = 0;
2637 return err;
2638 }
2639
2640 #endif
2641
2642 #if HAVE_OPENCL_DRM_ARM
2643
2644 typedef struct DRMARMtoOpenCLMapping {
2645 int nb_objects;
2646 cl_mem object_buffers[AV_DRM_MAX_PLANES];
2647 int nb_planes;
2648 cl_mem plane_images[AV_DRM_MAX_PLANES];
2649 } DRMARMtoOpenCLMapping;
2650
opencl_unmap_from_drm_arm(AVHWFramesContext * dst_fc,HWMapDescriptor * hwmap)2651 static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc,
2652 HWMapDescriptor *hwmap)
2653 {
2654 DRMARMtoOpenCLMapping *mapping = hwmap->priv;
2655 int i;
2656
2657 for (i = 0; i < mapping->nb_planes; i++)
2658 clReleaseMemObject(mapping->plane_images[i]);
2659
2660 for (i = 0; i < mapping->nb_objects; i++)
2661 clReleaseMemObject(mapping->object_buffers[i]);
2662
2663 av_free(mapping);
2664 }
2665
opencl_map_from_drm_arm(AVHWFramesContext * dst_fc,AVFrame * dst,const AVFrame * src,int flags)2666 static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst,
2667 const AVFrame *src, int flags)
2668 {
2669 AVHWFramesContext *src_fc =
2670 (AVHWFramesContext*)src->hw_frames_ctx->data;
2671 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2672 const AVDRMFrameDescriptor *desc;
2673 DRMARMtoOpenCLMapping *mapping = NULL;
2674 cl_mem_flags cl_flags;
2675 const cl_import_properties_arm props[3] = {
2676 CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0,
2677 };
2678 cl_int cle;
2679 int err, i, j;
2680
2681 desc = (const AVDRMFrameDescriptor*)src->data[0];
2682
2683 cl_flags = opencl_mem_flags_for_mapping(flags);
2684 if (!cl_flags)
2685 return AVERROR(EINVAL);
2686
2687 mapping = av_mallocz(sizeof(*mapping));
2688 if (!mapping)
2689 return AVERROR(ENOMEM);
2690
2691 mapping->nb_objects = desc->nb_objects;
2692 for (i = 0; i < desc->nb_objects; i++) {
2693 int fd = desc->objects[i].fd;
2694
2695 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd);
2696
2697 if (desc->objects[i].format_modifier) {
2698 av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has "
2699 "nonzero format modifier %"PRId64", result may not "
2700 "be as expected.\n", i, fd,
2701 desc->objects[i].format_modifier);
2702 }
2703
2704 mapping->object_buffers[i] =
2705 clImportMemoryARM(dst_dev->context, cl_flags, props,
2706 &fd, desc->objects[i].size, &cle);
2707 if (!mapping->object_buffers[i]) {
2708 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer "
2709 "from object %d (fd %d, size %"SIZE_SPECIFIER") of DRM frame: %d.\n",
2710 i, fd, desc->objects[i].size, cle);
2711 err = AVERROR(EIO);
2712 goto fail;
2713 }
2714 }
2715
2716 mapping->nb_planes = 0;
2717 for (i = 0; i < desc->nb_layers; i++) {
2718 const AVDRMLayerDescriptor *layer = &desc->layers[i];
2719
2720 for (j = 0; j < layer->nb_planes; j++) {
2721 const AVDRMPlaneDescriptor *plane = &layer->planes[j];
2722 cl_mem plane_buffer;
2723 cl_image_format image_format;
2724 cl_image_desc image_desc;
2725 cl_buffer_region region;
2726 int p = mapping->nb_planes;
2727
2728 err = opencl_get_plane_format(src_fc->sw_format, p,
2729 src_fc->width, src_fc->height,
2730 &image_format, &image_desc);
2731 if (err < 0) {
2732 av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM "
2733 "layer %d plane %d): %d.\n", p, i, j, err);
2734 goto fail;
2735 }
2736
2737 region.origin = plane->offset;
2738 region.size = image_desc.image_row_pitch *
2739 image_desc.image_height;
2740
2741 plane_buffer =
2742 clCreateSubBuffer(mapping->object_buffers[plane->object_index],
2743 cl_flags,
2744 CL_BUFFER_CREATE_TYPE_REGION,
2745 ®ion, &cle);
2746 if (!plane_buffer) {
2747 av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer "
2748 "for plane %d: %d.\n", p, cle);
2749 err = AVERROR(EIO);
2750 goto fail;
2751 }
2752
2753 image_desc.buffer = plane_buffer;
2754
2755 mapping->plane_images[p] =
2756 clCreateImage(dst_dev->context, cl_flags,
2757 &image_format, &image_desc, NULL, &cle);
2758
2759 // Unreference the sub-buffer immediately - we don't need it
2760 // directly and a reference is held by the image.
2761 clReleaseMemObject(plane_buffer);
2762
2763 if (!mapping->plane_images[p]) {
2764 av_log(dst_fc, AV_LOG_ERROR, "Failed to create image "
2765 "for plane %d: %d.\n", p, cle);
2766 err = AVERROR(EIO);
2767 goto fail;
2768 }
2769
2770 ++mapping->nb_planes;
2771 }
2772 }
2773
2774 for (i = 0; i < mapping->nb_planes; i++)
2775 dst->data[i] = (uint8_t*)mapping->plane_images[i];
2776
2777 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2778 &opencl_unmap_from_drm_arm, mapping);
2779 if (err < 0)
2780 goto fail;
2781
2782 dst->width = src->width;
2783 dst->height = src->height;
2784
2785 return 0;
2786
2787 fail:
2788 for (i = 0; i < mapping->nb_planes; i++) {
2789 clReleaseMemObject(mapping->plane_images[i]);
2790 }
2791 for (i = 0; i < mapping->nb_objects; i++) {
2792 if (mapping->object_buffers[i])
2793 clReleaseMemObject(mapping->object_buffers[i]);
2794 }
2795 av_free(mapping);
2796 return err;
2797 }
2798
2799 #endif
2800
opencl_map_from(AVHWFramesContext * hwfc,AVFrame * dst,const AVFrame * src,int flags)2801 static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
2802 const AVFrame *src, int flags)
2803 {
2804 av_assert0(src->format == AV_PIX_FMT_OPENCL);
2805 if (hwfc->sw_format != dst->format)
2806 return AVERROR(ENOSYS);
2807 return opencl_map_frame(hwfc, dst, src, flags);
2808 }
2809
opencl_map_to(AVHWFramesContext * hwfc,AVFrame * dst,const AVFrame * src,int flags)2810 static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2811 const AVFrame *src, int flags)
2812 {
2813 av_unused OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
2814 av_assert0(dst->format == AV_PIX_FMT_OPENCL);
2815 switch (src->format) {
2816 #if HAVE_OPENCL_DRM_BEIGNET
2817 case AV_PIX_FMT_DRM_PRIME:
2818 if (priv->beignet_drm_mapping_usable)
2819 return opencl_map_from_drm_beignet(hwfc, dst, src, flags);
2820 #endif
2821 #if HAVE_OPENCL_VAAPI_BEIGNET
2822 case AV_PIX_FMT_VAAPI:
2823 if (priv->beignet_drm_mapping_usable)
2824 return opencl_map_from_vaapi(hwfc, dst, src, flags);
2825 #endif
2826 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2827 case AV_PIX_FMT_QSV:
2828 case AV_PIX_FMT_VAAPI:
2829 if (priv->qsv_mapping_usable)
2830 return opencl_map_from_qsv(hwfc, dst, src, flags);
2831 #endif
2832 #if HAVE_OPENCL_DXVA2
2833 case AV_PIX_FMT_DXVA2_VLD:
2834 if (priv->dxva2_mapping_usable)
2835 return opencl_map_from_dxva2(hwfc, dst, src, flags);
2836 #endif
2837 #if HAVE_OPENCL_D3D11
2838 case AV_PIX_FMT_D3D11:
2839 if (priv->d3d11_mapping_usable)
2840 return opencl_map_from_d3d11(hwfc, dst, src, flags);
2841 #endif
2842 #if HAVE_OPENCL_DRM_ARM
2843 case AV_PIX_FMT_DRM_PRIME:
2844 if (priv->drm_arm_mapping_usable)
2845 return opencl_map_from_drm_arm(hwfc, dst, src, flags);
2846 #endif
2847 }
2848 return AVERROR(ENOSYS);
2849 }
2850
opencl_frames_derive_to(AVHWFramesContext * dst_fc,AVHWFramesContext * src_fc,int flags)2851 static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
2852 AVHWFramesContext *src_fc, int flags)
2853 {
2854 av_unused OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
2855 switch (src_fc->device_ctx->type) {
2856 #if HAVE_OPENCL_DRM_BEIGNET
2857 case AV_HWDEVICE_TYPE_DRM:
2858 if (!priv->beignet_drm_mapping_usable)
2859 return AVERROR(ENOSYS);
2860 break;
2861 #endif
2862 #if HAVE_OPENCL_VAAPI_BEIGNET
2863 case AV_HWDEVICE_TYPE_VAAPI:
2864 if (!priv->beignet_drm_mapping_usable)
2865 return AVERROR(ENOSYS);
2866 break;
2867 #endif
2868 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2869 case AV_HWDEVICE_TYPE_QSV:
2870 case AV_HWDEVICE_TYPE_VAAPI:
2871 if (!priv->qsv_mapping_usable)
2872 return AVERROR(ENOSYS);
2873 break;
2874 #endif
2875 #if HAVE_OPENCL_DXVA2
2876 case AV_HWDEVICE_TYPE_DXVA2:
2877 if (!priv->dxva2_mapping_usable)
2878 return AVERROR(ENOSYS);
2879 {
2880 int err;
2881 err = opencl_frames_derive_from_dxva2(dst_fc, src_fc, flags);
2882 if (err < 0)
2883 return err;
2884 }
2885 break;
2886 #endif
2887 #if HAVE_OPENCL_D3D11
2888 case AV_HWDEVICE_TYPE_D3D11VA:
2889 if (!priv->d3d11_mapping_usable)
2890 return AVERROR(ENOSYS);
2891 {
2892 int err;
2893 err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags);
2894 if (err < 0)
2895 return err;
2896 }
2897 break;
2898 #endif
2899 #if HAVE_OPENCL_DRM_ARM
2900 case AV_HWDEVICE_TYPE_DRM:
2901 if (!priv->drm_arm_mapping_usable)
2902 return AVERROR(ENOSYS);
2903 break;
2904 #endif
2905 default:
2906 return AVERROR(ENOSYS);
2907 }
2908 return opencl_frames_init_command_queue(dst_fc);
2909 }
2910
2911 const HWContextType ff_hwcontext_type_opencl = {
2912 .type = AV_HWDEVICE_TYPE_OPENCL,
2913 .name = "OpenCL",
2914
2915 .device_hwctx_size = sizeof(AVOpenCLDeviceContext),
2916 .device_priv_size = sizeof(OpenCLDeviceContext),
2917 .frames_hwctx_size = sizeof(AVOpenCLFramesContext),
2918 .frames_priv_size = sizeof(OpenCLFramesContext),
2919
2920 .device_create = &opencl_device_create,
2921 .device_derive = &opencl_device_derive,
2922 .device_init = &opencl_device_init,
2923 .device_uninit = &opencl_device_uninit,
2924
2925 .frames_get_constraints = &opencl_frames_get_constraints,
2926 .frames_init = &opencl_frames_init,
2927 .frames_uninit = &opencl_frames_uninit,
2928 .frames_get_buffer = &opencl_get_buffer,
2929
2930 .transfer_get_formats = &opencl_transfer_get_formats,
2931 .transfer_data_to = &opencl_transfer_data_to,
2932 .transfer_data_from = &opencl_transfer_data_from,
2933
2934 .map_from = &opencl_map_from,
2935 .map_to = &opencl_map_to,
2936 .frames_derive_to = &opencl_frames_derive_to,
2937
2938 .pix_fmts = (const enum AVPixelFormat[]) {
2939 AV_PIX_FMT_OPENCL,
2940 AV_PIX_FMT_NONE
2941 },
2942 };
2943