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