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