2 * This file is part of FFmpeg.
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.
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.
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
26 #include "hwcontext.h"
27 #include "hwcontext_internal.h"
28 #include "hwcontext_opencl.h"
32 #if HAVE_OPENCL_VAAPI_BEIGNET
35 #include <va/va_drmcommon.h>
36 #include <CL/cl_intel.h>
37 #include "hwcontext_vaapi.h"
40 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
41 #include <mfx/mfxstructures.h>
43 #include <CL/va_ext.h>
44 #include "hwcontext_vaapi.h"
48 typedef struct OpenCLDeviceContext {
49 // Default command queue to use for transfer/mapping operations on
50 // the device. If the user supplies one, this is a reference to it.
51 // Otherwise, it is newly-created.
52 cl_command_queue command_queue;
54 // The platform the context exists on. This is needed to query and
55 // retrieve extension functions.
56 cl_platform_id platform_id;
58 // Platform/device-specific functions.
59 #if HAVE_OPENCL_VAAPI_BEIGNET
60 int vaapi_mapping_usable;
61 clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL;
64 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
65 int qsv_mapping_usable;
66 clCreateFromVA_APIMediaSurfaceINTEL_fn
67 clCreateFromVA_APIMediaSurfaceINTEL;
68 clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
69 clEnqueueAcquireVA_APIMediaSurfacesINTEL;
70 clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
71 clEnqueueReleaseVA_APIMediaSurfacesINTEL;
73 } OpenCLDeviceContext;
75 typedef struct OpenCLFramesContext {
76 // Command queue used for transfer/mapping operations on this frames
77 // context. If the user supplies one, this is a reference to it.
78 // Otherwise, it is a reference to the default command queue for the
80 cl_command_queue command_queue;
81 } OpenCLFramesContext;
84 static void opencl_error_callback(const char *errinfo,
85 const void *private_info, size_t cb,
88 AVHWDeviceContext *ctx = user_data;
89 av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
92 static void opencl_device_free(AVHWDeviceContext *hwdev)
94 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
97 cle = clReleaseContext(hwctx->context);
98 if (cle != CL_SUCCESS) {
99 av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
100 "context: %d.\n", cle);
106 cl_platform_info name;
107 } opencl_platform_params[] = {
108 { "platform_profile", CL_PLATFORM_PROFILE },
109 { "platform_version", CL_PLATFORM_VERSION },
110 { "platform_name", CL_PLATFORM_NAME },
111 { "platform_vendor", CL_PLATFORM_VENDOR },
112 { "platform_extensions", CL_PLATFORM_EXTENSIONS },
118 } opencl_device_params[] = {
119 { "device_name", CL_DEVICE_NAME },
120 { "device_vendor", CL_DEVICE_VENDOR },
121 { "driver_version", CL_DRIVER_VERSION },
122 { "device_version", CL_DEVICE_VERSION },
123 { "device_profile", CL_DEVICE_PROFILE },
124 { "device_extensions", CL_DEVICE_EXTENSIONS },
130 } opencl_device_types[] = {
131 { "cpu", CL_DEVICE_TYPE_CPU },
132 { "gpu", CL_DEVICE_TYPE_GPU },
133 { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
134 { "custom", CL_DEVICE_TYPE_CUSTOM },
135 { "default", CL_DEVICE_TYPE_DEFAULT },
136 { "all", CL_DEVICE_TYPE_ALL },
139 static char *opencl_get_platform_string(cl_platform_id platform_id,
140 cl_platform_info key)
145 cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
146 if (cle != CL_SUCCESS)
148 str = av_malloc(size);
151 cle = clGetPlatformInfo(platform_id, key, size, str, &size);
152 if (cle != CL_SUCCESS) {
156 av_assert0(strlen(str) + 1 == size);
160 static char *opencl_get_device_string(cl_device_id device_id,
166 cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
167 if (cle != CL_SUCCESS)
169 str = av_malloc(size);
172 cle = clGetDeviceInfo(device_id, key, size, str, &size);
173 if (cle != CL_SUCCESS) {
177 av_assert0(strlen(str) + 1== size);
181 static int opencl_check_platform_extension(cl_platform_id platform_id,
186 str = opencl_get_platform_string(platform_id,
187 CL_PLATFORM_EXTENSIONS);
188 if (str && strstr(str, name))
194 static int opencl_check_device_extension(cl_device_id device_id,
199 str = opencl_get_device_string(device_id,
200 CL_DEVICE_EXTENSIONS);
201 if (str && strstr(str, name))
207 static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
210 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
211 OpenCLDeviceContext *priv = hwdev->internal->priv;
213 if (opencl_check_platform_extension(priv->platform_id, name)) {
214 av_log(hwdev, AV_LOG_DEBUG,
215 "%s found as platform extension.\n", name);
219 if (opencl_check_device_extension(hwctx->device_id, name)) {
220 av_log(hwdev, AV_LOG_DEBUG,
221 "%s found as device extension.\n", name);
228 static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
229 cl_uint *nb_platforms,
230 cl_platform_id **platforms,
235 cle = clGetPlatformIDs(0, NULL, nb_platforms);
236 if (cle != CL_SUCCESS) {
237 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
238 "OpenCL platforms: %d.\n", cle);
239 return AVERROR(ENODEV);
241 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
244 *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
246 return AVERROR(ENOMEM);
248 cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
249 if (cle != CL_SUCCESS) {
250 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
251 "platforms: %d.\n", cle);
253 return AVERROR(ENODEV);
259 static int opencl_filter_platform(AVHWDeviceContext *hwdev,
260 cl_platform_id platform_id,
261 const char *platform_name,
264 AVDictionary *opts = context;
265 const AVDictionaryEntry *param;
269 for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
270 param = av_dict_get(opts, opencl_platform_params[i].key,
275 str = opencl_get_platform_string(platform_id,
276 opencl_platform_params[i].name);
278 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
279 "of platform \"%s\".\n",
280 opencl_platform_params[i].key, platform_name);
281 return AVERROR_UNKNOWN;
283 if (!av_stristr(str, param->value)) {
284 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
294 static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
295 cl_platform_id platform_id,
296 const char *platform_name,
298 cl_device_id **devices,
303 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
304 0, NULL, nb_devices);
305 if (cle == CL_DEVICE_NOT_FOUND) {
306 av_log(hwdev, AV_LOG_DEBUG, "No devices found "
307 "on platform \"%s\".\n", platform_name);
310 } else if (cle != CL_SUCCESS) {
311 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
312 "on platform \"%s\": %d.\n", platform_name, cle);
313 return AVERROR(ENODEV);
315 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
316 "platform \"%s\".\n", *nb_devices, platform_name);
318 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
320 return AVERROR(ENOMEM);
322 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
323 *nb_devices, *devices, NULL);
324 if (cle != CL_SUCCESS) {
325 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
326 "on platform \"%s\": %d.\n", platform_name, cle);
328 return AVERROR(ENODEV);
334 static int opencl_filter_device(AVHWDeviceContext *hwdev,
335 cl_device_id device_id,
336 const char *device_name,
339 AVDictionary *opts = context;
340 const AVDictionaryEntry *param;
344 param = av_dict_get(opts, "device_type", NULL, 0);
346 cl_device_type match_type = 0, device_type;
349 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
350 if (!strcmp(opencl_device_types[i].key, param->value)) {
351 match_type = opencl_device_types[i].type;
356 av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
358 return AVERROR(EINVAL);
361 cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
362 sizeof(device_type), &device_type, NULL);
363 if (cle != CL_SUCCESS) {
364 av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
365 "of device \"%s\".\n", device_name);
366 return AVERROR_UNKNOWN;
369 if (!(device_type & match_type)) {
370 av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
375 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
376 param = av_dict_get(opts, opencl_device_params[i].key,
381 str = opencl_get_device_string(device_id,
382 opencl_device_params[i].name);
384 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
385 "of device \"%s\".\n",
386 opencl_device_params[i].key, device_name);
387 return AVERROR_UNKNOWN;
389 if (!av_stristr(str, param->value)) {
390 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
400 typedef struct OpenCLDeviceSelector {
404 int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
405 cl_uint *nb_platforms,
406 cl_platform_id **platforms,
408 int (*filter_platform) (AVHWDeviceContext *hwdev,
409 cl_platform_id platform_id,
410 const char *platform_name,
412 int (*enumerate_devices) (AVHWDeviceContext *hwdev,
413 cl_platform_id platform_id,
414 const char *platform_name,
416 cl_device_id **devices,
418 int (*filter_device) (AVHWDeviceContext *hwdev,
419 cl_device_id device_id,
420 const char *device_name,
422 } OpenCLDeviceSelector;
424 static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
425 const OpenCLDeviceSelector *selector,
426 cl_context_properties *props)
428 cl_uint nb_platforms;
429 cl_platform_id *platforms = NULL;
430 cl_platform_id platform_id;
432 cl_device_id *devices = NULL;
433 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
435 cl_context_properties default_props[3];
436 char *platform_name_src = NULL,
437 *device_name_src = NULL;
438 int err, found, p, d;
440 err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
446 for (p = 0; p < nb_platforms; p++) {
447 const char *platform_name;
449 if (selector->platform_index >= 0 &&
450 selector->platform_index != p)
453 av_freep(&platform_name_src);
454 platform_name_src = opencl_get_platform_string(platforms[p],
456 if (platform_name_src)
457 platform_name = platform_name_src;
459 platform_name = "Unknown Platform";
461 if (selector->filter_platform) {
462 err = selector->filter_platform(hwdev, platforms[p],
471 err = opencl_enumerate_devices(hwdev, platforms[p], platform_name,
472 &nb_devices, &devices,
477 for (d = 0; d < nb_devices; d++) {
478 const char *device_name;
480 if (selector->device_index >= 0 &&
481 selector->device_index != d)
484 av_freep(&device_name_src);
485 device_name_src = opencl_get_device_string(devices[d],
488 device_name = device_name_src;
490 device_name = "Unknown Device";
492 if (selector->filter_device) {
493 err = selector->filter_device(hwdev, devices[d],
502 av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
503 platform_name, device_name);
506 platform_id = platforms[p];
507 hwctx->device_id = devices[d];
514 av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
515 err = AVERROR(ENODEV);
519 av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
520 err = AVERROR(ENODEV);
525 props = default_props;
526 default_props[0] = CL_CONTEXT_PLATFORM;
527 default_props[1] = (intptr_t)platform_id;
528 default_props[2] = 0;
530 if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
531 props[1] = (intptr_t)platform_id;
534 hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
535 &opencl_error_callback, hwdev, &cle);
536 if (!hwctx->context) {
537 av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
539 err = AVERROR(ENODEV);
543 hwdev->free = &opencl_device_free;
547 av_freep(&platform_name_src);
548 av_freep(&device_name_src);
549 av_freep(&platforms);
554 static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
555 AVDictionary *opts, int flags)
557 OpenCLDeviceSelector selector = {
559 .enumerate_platforms = &opencl_enumerate_platforms,
560 .filter_platform = &opencl_filter_platform,
561 .enumerate_devices = &opencl_enumerate_devices,
562 .filter_device = &opencl_filter_device,
565 if (device && device[0]) {
566 // Match one or both indices for platform and device.
567 int d = -1, p = -1, ret;
568 if (device[0] == '.')
569 ret = sscanf(device, ".%d", &d);
571 ret = sscanf(device, "%d.%d", &p, &d);
573 av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
574 "index specification \"%s\".\n", device);
575 return AVERROR(EINVAL);
577 selector.platform_index = p;
578 selector.device_index = d;
580 selector.platform_index = -1;
581 selector.device_index = -1;
584 return opencl_device_create_internal(hwdev, &selector, NULL);
587 static int opencl_device_init(AVHWDeviceContext *hwdev)
589 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
590 OpenCLDeviceContext *priv = hwdev->internal->priv;
593 if (hwctx->command_queue) {
594 cle = clRetainCommandQueue(hwctx->command_queue);
595 if (cle != CL_SUCCESS) {
596 av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
597 "command queue: %d.\n", cle);
600 priv->command_queue = hwctx->command_queue;
602 priv->command_queue = clCreateCommandQueue(hwctx->context,
605 if (!priv->command_queue) {
606 av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
607 "command queue: %d.\n", cle);
612 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
613 sizeof(priv->platform_id), &priv->platform_id,
615 if (cle != CL_SUCCESS) {
616 av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
617 "platform containing the device.\n");
621 #define CL_FUNC(name, desc) do { \
624 priv->name = clGetExtensionFunctionAddressForPlatform( \
625 priv->platform_id, #name); \
627 av_log(hwdev, AV_LOG_VERBOSE, \
628 desc " function not found (%s).\n", #name); \
631 av_log(hwdev, AV_LOG_VERBOSE, \
632 desc " function found (%s).\n", #name); \
636 #if HAVE_OPENCL_VAAPI_BEIGNET
640 CL_FUNC(clCreateImageFromFdINTEL,
641 "Intel DRM to OpenCL image mapping");
644 av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping "
646 priv->vaapi_mapping_usable = 0;
648 priv->vaapi_mapping_usable = 1;
653 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
656 cl_context_properties *props = NULL;
657 VADisplay va_display;
658 const char *va_ext = "cl_intel_va_api_media_sharing";
661 if (!opencl_check_extension(hwdev, va_ext)) {
662 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
663 "required for QSV to OpenCL mapping.\n", va_ext);
667 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
668 0, NULL, &props_size);
669 if (cle != CL_SUCCESS) {
670 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
671 "properties: %d.\n", cle);
674 if (props_size == 0) {
675 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
676 "enabled on context creation to use QSV to "
677 "OpenCL mapping.\n");
681 props = av_malloc(props_size);
683 return AVERROR(ENOMEM);
685 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
686 props_size, props, NULL);
687 if (cle != CL_SUCCESS) {
688 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
689 "properties: %d.\n", cle);
694 for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
695 if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
696 va_display = (VADisplay)(intptr_t)props[i+1];
701 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
702 "enabled on context creation to use QSV to "
703 "OpenCL mapping.\n");
706 if (!vaDisplayIsValid(va_display)) {
707 av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is "
708 "required on context creation to use QSV to "
709 "OpenCL mapping.\n");
713 CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
714 "Intel QSV to OpenCL mapping");
715 CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
716 "Intel QSV in OpenCL acquire");
717 CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
718 "Intel QSV in OpenCL release");
722 av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping "
724 priv->qsv_mapping_usable = 0;
726 priv->qsv_mapping_usable = 1;
737 static void opencl_device_uninit(AVHWDeviceContext *hwdev)
739 OpenCLDeviceContext *priv = hwdev->internal->priv;
742 if (priv->command_queue) {
743 cle = clReleaseCommandQueue(priv->command_queue);
744 if (cle != CL_SUCCESS) {
745 av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
746 "command queue reference: %d.\n", cle);
751 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
752 static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev,
753 cl_platform_id platform_id,
754 const char *platform_name,
757 // This doesn't exist as a platform extension, so just test whether
758 // the function we will use for device enumeration exists.
760 if (!clGetExtensionFunctionAddressForPlatform(platform_id,
761 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) {
762 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the "
763 "VAAPI device enumeration function.\n", platform_name);
770 static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev,
771 cl_platform_id platform_id,
772 const char *platform_name,
774 cl_device_id **devices,
777 VADisplay va_display = context;
778 clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn
779 clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
783 clGetDeviceIDsFromVA_APIMediaAdapterINTEL =
784 clGetExtensionFunctionAddressForPlatform(platform_id,
785 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
786 if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) {
787 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
788 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n");
789 return AVERROR_UNKNOWN;
792 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
793 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
794 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices);
795 if (cle == CL_DEVICE_NOT_FOUND) {
796 av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found "
797 "on platform \"%s\".\n", platform_name);
800 } else if (cle != CL_SUCCESS) {
801 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
802 "on platform \"%s\": %d.\n", platform_name, cle);
803 return AVERROR_UNKNOWN;
806 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
808 return AVERROR(ENOMEM);
810 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
811 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
812 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL);
813 if (cle != CL_SUCCESS) {
814 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting "
815 "devices on platform \"%s\": %d.\n", platform_name, cle);
817 return AVERROR_UNKNOWN;
823 static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev,
824 cl_device_id device_id,
825 const char *device_name,
828 const char *va_ext = "cl_intel_va_api_media_sharing";
830 if (opencl_check_device_extension(device_id, va_ext)) {
833 av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
834 "%s extension.\n", device_name, va_ext);
840 static int opencl_device_derive(AVHWDeviceContext *hwdev,
841 AVHWDeviceContext *src_ctx,
845 switch (src_ctx->type) {
847 #if HAVE_OPENCL_VAAPI_BEIGNET
848 case AV_HWDEVICE_TYPE_VAAPI:
850 // Surface mapping works via DRM PRIME fds with no special
851 // initialisation required in advance. This just finds the
852 // Beignet ICD by name.
853 AVDictionary *opts = NULL;
855 err = av_dict_set(&opts, "platform_vendor", "Intel", 0);
857 err = av_dict_set(&opts, "platform_version", "beignet", 0);
859 OpenCLDeviceSelector selector = {
860 .platform_index = -1,
863 .enumerate_platforms = &opencl_enumerate_platforms,
864 .filter_platform = &opencl_filter_platform,
865 .enumerate_devices = &opencl_enumerate_devices,
866 .filter_device = NULL,
868 err = opencl_device_create_internal(hwdev, &selector, NULL);
875 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
876 // The generic code automatically attempts to derive from all
877 // ancestors of the given device, so we can ignore QSV devices here
878 // and just consider the inner VAAPI device it was derived from.
879 case AV_HWDEVICE_TYPE_VAAPI:
881 AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
882 cl_context_properties props[7] = {
885 CL_CONTEXT_VA_API_DISPLAY_INTEL,
886 (intptr_t)src_hwctx->display,
887 CL_CONTEXT_INTEROP_USER_SYNC,
891 OpenCLDeviceSelector selector = {
892 .platform_index = -1,
894 .context = src_hwctx->display,
895 .enumerate_platforms = &opencl_enumerate_platforms,
896 .filter_platform = &opencl_filter_intel_media_vaapi_platform,
897 .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices,
898 .filter_device = &opencl_filter_intel_media_vaapi_device,
901 err = opencl_device_create_internal(hwdev, &selector, props);
907 err = AVERROR(ENOSYS);
914 return opencl_device_init(hwdev);
917 static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
918 int plane, int width, int height,
919 cl_image_format *image_format,
920 cl_image_desc *image_desc)
922 const AVPixFmtDescriptor *desc;
923 const AVComponentDescriptor *comp;
924 int channels = 0, order = 0, depth = 0, step = 0;
925 int wsub, hsub, alpha;
928 if (plane >= AV_NUM_DATA_POINTERS)
929 return AVERROR(ENOENT);
931 desc = av_pix_fmt_desc_get(pixfmt);
933 // Only normal images are allowed.
934 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
935 AV_PIX_FMT_FLAG_HWACCEL |
936 AV_PIX_FMT_FLAG_PAL))
937 return AVERROR(EINVAL);
939 wsub = 1 << desc->log2_chroma_w;
940 hsub = 1 << desc->log2_chroma_h;
941 // Subsampled components must be exact.
942 if (width & wsub - 1 || height & hsub - 1)
943 return AVERROR(EINVAL);
945 for (c = 0; c < desc->nb_components; c++) {
946 comp = &desc->comp[c];
947 if (comp->plane != plane)
949 // The step size must be a power of two.
950 if (comp->step != 1 && comp->step != 2 &&
951 comp->step != 4 && comp->step != 8)
952 return AVERROR(EINVAL);
953 // The bits in each component must be packed in the
954 // most-significant-bits of the relevant bytes.
955 if (comp->shift + comp->depth != 8 &&
956 comp->shift + comp->depth != 16)
957 return AVERROR(EINVAL);
958 // The depth must not vary between components.
959 if (depth && comp->depth != depth)
960 return AVERROR(EINVAL);
961 // If a single data element crosses multiple bytes then
962 // it must match the native endianness.
963 if (comp->depth > 8 &&
964 HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
965 return AVERROR(EINVAL);
966 // A single data element must not contain multiple samples
967 // from the same component.
968 if (step && comp->step != step)
969 return AVERROR(EINVAL);
970 order = order * 10 + c + 1;
973 alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
974 c == desc->nb_components - 1);
978 return AVERROR(ENOENT);
980 memset(image_format, 0, sizeof(*image_format));
981 memset(image_desc, 0, sizeof(*image_desc));
982 image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
984 if (plane == 0 || alpha) {
985 image_desc->image_width = width;
986 image_desc->image_height = height;
987 image_desc->image_row_pitch = step * width;
989 image_desc->image_width = width / wsub;
990 image_desc->image_height = height / hsub;
991 image_desc->image_row_pitch = step * width / wsub;
995 image_format->image_channel_data_type = CL_UNORM_INT8;
998 image_format->image_channel_data_type = CL_UNORM_INT16;
1000 return AVERROR(EINVAL);
1003 #define CHANNEL_ORDER(order, type) \
1004 case order: image_format->image_channel_order = type; break;
1006 CHANNEL_ORDER(1, CL_R);
1007 CHANNEL_ORDER(2, CL_R);
1008 CHANNEL_ORDER(3, CL_R);
1009 CHANNEL_ORDER(4, CL_R);
1010 CHANNEL_ORDER(12, CL_RG);
1011 CHANNEL_ORDER(23, CL_RG);
1012 CHANNEL_ORDER(1234, CL_RGBA);
1013 CHANNEL_ORDER(3214, CL_BGRA);
1014 CHANNEL_ORDER(4123, CL_ARGB);
1016 CHANNEL_ORDER(4321, CL_ABGR);
1019 return AVERROR(EINVAL);
1021 #undef CHANNEL_ORDER
1026 static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
1027 const void *hwconfig,
1028 AVHWFramesConstraints *constraints)
1030 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
1031 cl_uint nb_image_formats;
1032 cl_image_format *image_formats = NULL;
1034 enum AVPixelFormat pix_fmt;
1035 int err, pix_fmts_found;
1036 size_t max_width, max_height;
1038 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
1039 sizeof(max_width), &max_width, NULL);
1040 if (cle != CL_SUCCESS) {
1041 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1042 "supported image width: %d.\n", cle);
1044 constraints->max_width = max_width;
1046 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
1047 sizeof(max_height), &max_height, NULL);
1048 if (cle != CL_SUCCESS) {
1049 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1050 "supported image height: %d.\n", cle);
1052 constraints->max_height = max_height;
1054 av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
1055 constraints->max_width, constraints->max_height);
1057 cle = clGetSupportedImageFormats(hwctx->context,
1059 CL_MEM_OBJECT_IMAGE2D,
1060 0, NULL, &nb_image_formats);
1061 if (cle != CL_SUCCESS) {
1062 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1063 "image formats: %d.\n", cle);
1064 err = AVERROR(ENOSYS);
1067 if (nb_image_formats == 0) {
1068 av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
1069 "driver (zero supported image formats).\n");
1070 err = AVERROR(ENOSYS);
1075 av_malloc_array(nb_image_formats, sizeof(*image_formats));
1076 if (!image_formats) {
1077 err = AVERROR(ENOMEM);
1081 cle = clGetSupportedImageFormats(hwctx->context,
1083 CL_MEM_OBJECT_IMAGE2D,
1085 image_formats, NULL);
1086 if (cle != CL_SUCCESS) {
1087 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1088 "image formats: %d.\n", cle);
1089 err = AVERROR(ENOSYS);
1094 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
1095 cl_image_format image_format;
1096 cl_image_desc image_desc;
1099 for (plane = 0;; plane++) {
1100 err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
1106 for (i = 0; i < nb_image_formats; i++) {
1107 if (image_formats[i].image_channel_order ==
1108 image_format.image_channel_order &&
1109 image_formats[i].image_channel_data_type ==
1110 image_format.image_channel_data_type)
1113 if (i == nb_image_formats) {
1114 err = AVERROR(EINVAL);
1118 if (err != AVERROR(ENOENT))
1121 av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
1122 av_get_pix_fmt_name(pix_fmt));
1124 err = av_reallocp_array(&constraints->valid_sw_formats,
1126 sizeof(*constraints->valid_sw_formats));
1129 constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
1130 constraints->valid_sw_formats[pix_fmts_found + 1] =
1135 av_freep(&image_formats);
1137 constraints->valid_hw_formats =
1138 av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
1139 if (!constraints->valid_hw_formats) {
1140 err = AVERROR(ENOMEM);
1143 constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
1144 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1149 av_freep(&image_formats);
1153 static void opencl_pool_free(void *opaque, uint8_t *data)
1155 AVHWFramesContext *hwfc = opaque;
1156 AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
1160 for (p = 0; p < desc->nb_planes; p++) {
1161 cle = clReleaseMemObject(desc->planes[p]);
1162 if (cle != CL_SUCCESS) {
1163 av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
1171 static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
1173 AVHWFramesContext *hwfc = opaque;
1174 AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1175 AVOpenCLFrameDescriptor *desc;
1178 cl_image_format image_format;
1179 cl_image_desc image_desc;
1183 desc = av_mallocz(sizeof(*desc));
1188 err = opencl_get_plane_format(hwfc->sw_format, p,
1189 hwfc->width, hwfc->height,
1190 &image_format, &image_desc);
1191 if (err == AVERROR(ENOENT))
1196 // For generic image objects, the pitch is determined by the
1198 image_desc.image_row_pitch = 0;
1200 image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
1201 &image_format, &image_desc, NULL, &cle);
1203 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
1204 "plane %d: %d.\n", p, cle);
1208 desc->planes[p] = image;
1211 desc->nb_planes = p;
1213 ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
1214 &opencl_pool_free, hwfc, 0);
1221 for (p = 0; desc->planes[p]; p++)
1222 clReleaseMemObject(desc->planes[p]);
1227 static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
1229 AVOpenCLFramesContext *hwctx = hwfc->hwctx;
1230 OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
1231 OpenCLFramesContext *priv = hwfc->internal->priv;
1234 priv->command_queue = hwctx->command_queue ? hwctx->command_queue
1235 : devpriv->command_queue;
1236 cle = clRetainCommandQueue(priv->command_queue);
1237 if (cle != CL_SUCCESS) {
1238 av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
1239 "command queue: %d.\n", cle);
1240 return AVERROR(EIO);
1246 static int opencl_frames_init(AVHWFramesContext *hwfc)
1249 hwfc->internal->pool_internal =
1250 av_buffer_pool_init2(sizeof(cl_mem), hwfc,
1251 &opencl_pool_alloc, NULL);
1252 if (!hwfc->internal->pool_internal)
1253 return AVERROR(ENOMEM);
1256 return opencl_frames_init_command_queue(hwfc);
1259 static void opencl_frames_uninit(AVHWFramesContext *hwfc)
1261 OpenCLFramesContext *priv = hwfc->internal->priv;
1264 cle = clReleaseCommandQueue(priv->command_queue);
1265 if (cle != CL_SUCCESS) {
1266 av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
1267 "command queue: %d.\n", cle);
1271 static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
1273 AVOpenCLFrameDescriptor *desc;
1276 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1278 return AVERROR(ENOMEM);
1280 desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
1282 for (p = 0; p < desc->nb_planes; p++)
1283 frame->data[p] = (uint8_t*)desc->planes[p];
1285 frame->format = AV_PIX_FMT_OPENCL;
1286 frame->width = hwfc->width;
1287 frame->height = hwfc->height;
1292 static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
1293 enum AVHWFrameTransferDirection dir,
1294 enum AVPixelFormat **formats)
1296 enum AVPixelFormat *fmts;
1298 fmts = av_malloc_array(2, sizeof(*fmts));
1300 return AVERROR(ENOMEM);
1302 fmts[0] = hwfc->sw_format;
1303 fmts[1] = AV_PIX_FMT_NONE;
1309 static int opencl_wait_events(AVHWFramesContext *hwfc,
1310 cl_event *events, int nb_events)
1315 cle = clWaitForEvents(nb_events, events);
1316 if (cle != CL_SUCCESS) {
1317 av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
1318 "completion: %d.\n", cle);
1319 return AVERROR(EIO);
1322 for (i = 0; i < nb_events; i++) {
1323 cle = clReleaseEvent(events[i]);
1324 if (cle != CL_SUCCESS) {
1325 av_log(hwfc, AV_LOG_ERROR, "Failed to release "
1326 "event: %d.\n", cle);
1333 static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
1334 AVFrame *dst, const AVFrame *src)
1336 OpenCLFramesContext *priv = hwfc->internal->priv;
1337 cl_image_format image_format;
1338 cl_image_desc image_desc;
1340 size_t origin[3] = { 0, 0, 0 };
1342 cl_event events[AV_NUM_DATA_POINTERS];
1345 if (dst->format != hwfc->sw_format)
1346 return AVERROR(EINVAL);
1349 err = opencl_get_plane_format(hwfc->sw_format, p,
1350 src->width, src->height,
1351 &image_format, &image_desc);
1353 if (err == AVERROR(ENOENT))
1358 if (!dst->data[p]) {
1359 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1360 "destination frame for transfer.\n", p);
1361 err = AVERROR(EINVAL);
1365 region[0] = image_desc.image_width;
1366 region[1] = image_desc.image_height;
1369 cle = clEnqueueReadImage(priv->command_queue,
1370 (cl_mem)src->data[p],
1371 CL_FALSE, origin, region,
1372 dst->linesize[p], 0,
1374 0, NULL, &events[p]);
1375 if (cle != CL_SUCCESS) {
1376 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
1377 "OpenCL image plane %d: %d.\n", p, cle);
1383 opencl_wait_events(hwfc, events, p);
1388 static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
1389 AVFrame *dst, const AVFrame *src)
1391 OpenCLFramesContext *priv = hwfc->internal->priv;
1392 cl_image_format image_format;
1393 cl_image_desc image_desc;
1395 size_t origin[3] = { 0, 0, 0 };
1397 cl_event events[AV_NUM_DATA_POINTERS];
1400 if (src->format != hwfc->sw_format)
1401 return AVERROR(EINVAL);
1404 err = opencl_get_plane_format(hwfc->sw_format, p,
1405 src->width, src->height,
1406 &image_format, &image_desc);
1408 if (err == AVERROR(ENOENT))
1413 if (!src->data[p]) {
1414 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1415 "source frame for transfer.\n", p);
1416 err = AVERROR(EINVAL);
1420 region[0] = image_desc.image_width;
1421 region[1] = image_desc.image_height;
1424 cle = clEnqueueWriteImage(priv->command_queue,
1425 (cl_mem)dst->data[p],
1426 CL_FALSE, origin, region,
1427 src->linesize[p], 0,
1429 0, NULL, &events[p]);
1430 if (cle != CL_SUCCESS) {
1431 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
1432 "OpenCL image plane %d: %d.\n", p, cle);
1438 opencl_wait_events(hwfc, events, p);
1443 typedef struct OpenCLMapping {
1444 // The mapped addresses for each plane.
1445 // The destination frame is not available when we unmap, so these
1446 // need to be stored separately.
1447 void *address[AV_NUM_DATA_POINTERS];
1450 static void opencl_unmap_frame(AVHWFramesContext *hwfc,
1451 HWMapDescriptor *hwmap)
1453 OpenCLFramesContext *priv = hwfc->internal->priv;
1454 OpenCLMapping *map = hwmap->priv;
1455 cl_event events[AV_NUM_DATA_POINTERS];
1459 for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
1460 if (!map->address[p])
1463 cle = clEnqueueUnmapMemObject(priv->command_queue,
1464 (cl_mem)hwmap->source->data[p],
1466 0, NULL, &events[e]);
1467 if (cle != CL_SUCCESS) {
1468 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
1469 "image plane %d: %d.\n", p, cle);
1474 opencl_wait_events(hwfc, events, e);
1479 static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
1480 const AVFrame *src, int flags)
1482 OpenCLFramesContext *priv = hwfc->internal->priv;
1483 cl_map_flags map_flags;
1484 cl_image_format image_format;
1485 cl_image_desc image_desc;
1488 size_t origin[3] = { 0, 0, 0 };
1491 cl_event events[AV_NUM_DATA_POINTERS];
1494 av_assert0(hwfc->sw_format == dst->format);
1496 if (flags & AV_HWFRAME_MAP_OVERWRITE &&
1497 !(flags & AV_HWFRAME_MAP_READ)) {
1498 // This is mutually exclusive with the read/write flags, so
1499 // there is no way to map with read here.
1500 map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
1503 if (flags & AV_HWFRAME_MAP_READ)
1504 map_flags |= CL_MAP_READ;
1505 if (flags & AV_HWFRAME_MAP_WRITE)
1506 map_flags |= CL_MAP_WRITE;
1509 map = av_mallocz(sizeof(*map));
1511 return AVERROR(ENOMEM);
1514 err = opencl_get_plane_format(hwfc->sw_format, p,
1515 src->width, src->height,
1516 &image_format, &image_desc);
1517 if (err == AVERROR(ENOENT))
1522 region[0] = image_desc.image_width;
1523 region[1] = image_desc.image_height;
1527 clEnqueueMapImage(priv->command_queue,
1528 (cl_mem)src->data[p],
1529 CL_FALSE, map_flags, origin, region,
1530 &row_pitch, NULL, 0, NULL,
1532 if (!map->address[p]) {
1533 av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
1534 "image plane %d: %d.\n", p, cle);
1539 dst->data[p] = map->address[p];
1541 av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
1542 p, src->data[p], dst->data[p]);
1545 err = opencl_wait_events(hwfc, events, p);
1549 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1550 &opencl_unmap_frame, map);
1554 dst->width = src->width;
1555 dst->height = src->height;
1560 for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
1561 if (!map->address[p])
1563 clEnqueueUnmapMemObject(priv->command_queue,
1564 (cl_mem)src->data[p],
1566 0, NULL, &events[p]);
1569 opencl_wait_events(hwfc, events, p);
1574 #if HAVE_OPENCL_VAAPI_BEIGNET
1576 typedef struct VAAPItoOpenCLMapping {
1578 VABufferInfo va_buffer_info;
1580 AVOpenCLFrameDescriptor frame;
1581 } VAAPItoOpenCLMapping;
1583 static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc,
1584 HWMapDescriptor *hwmap)
1586 VAAPItoOpenCLMapping *mapping = hwmap->priv;
1587 AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
1588 VASurfaceID surface_id;
1593 surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1594 av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
1597 for (i = 0; i < mapping->frame.nb_planes; i++) {
1598 cle = clReleaseMemObject(mapping->frame.planes[i]);
1599 if (cle != CL_SUCCESS) {
1600 av_log(src_fc, AV_LOG_ERROR, "Failed to release CL "
1601 "buffer of plane %d of VA image %#x (derived "
1602 "from surface %#x): %d.\n", i,
1603 mapping->va_image.buf, surface_id, cle);
1607 vas = vaReleaseBufferHandle(src_dev->display,
1608 mapping->va_image.buf);
1609 if (vas != VA_STATUS_SUCCESS) {
1610 av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
1611 "handle of image %#x (derived from surface %#x): "
1612 "%d (%s).\n", mapping->va_image.buf, surface_id,
1613 vas, vaErrorStr(vas));
1616 vas = vaDestroyImage(src_dev->display,
1617 mapping->va_image.image_id);
1618 if (vas != VA_STATUS_SUCCESS) {
1619 av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
1620 "derived from surface %#x: %d (%s).\n",
1621 surface_id, vas, vaErrorStr(vas));
1627 static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst,
1628 const AVFrame *src, int flags)
1630 AVHWFramesContext *src_fc =
1631 (AVHWFramesContext*)src->hw_frames_ctx->data;
1632 AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
1633 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1634 OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
1635 VAAPItoOpenCLMapping *mapping = NULL;
1636 VASurfaceID surface_id;
1641 surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1642 av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
1645 mapping = av_mallocz(sizeof(*mapping));
1647 return AVERROR(ENOMEM);
1649 vas = vaDeriveImage(src_dev->display, surface_id,
1650 &mapping->va_image);
1651 if (vas != VA_STATUS_SUCCESS) {
1652 av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from "
1653 "surface %#x: %d (%s).\n",
1654 surface_id, vas, vaErrorStr(vas));
1659 mapping->va_buffer_info.mem_type =
1660 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1662 vas = vaAcquireBufferHandle(src_dev->display,
1663 mapping->va_image.buf,
1664 &mapping->va_buffer_info);
1665 if (vas != VA_STATUS_SUCCESS) {
1666 av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer "
1667 "handle from image %#x (derived from surface %#x): "
1668 "%d (%s).\n", mapping->va_image.buf, surface_id,
1669 vas, vaErrorStr(vas));
1670 vaDestroyImage(src_dev->display, mapping->va_image.buf);
1675 av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1676 mapping->va_buffer_info.handle);
1678 mapping->frame.nb_planes = mapping->va_image.num_planes;
1679 for (p = 0; p < mapping->frame.nb_planes; p++) {
1680 cl_import_image_info_intel image_info = {
1681 .fd = mapping->va_buffer_info.handle,
1682 .size = mapping->va_buffer_info.mem_size,
1683 .type = CL_MEM_OBJECT_IMAGE2D,
1684 .offset = mapping->va_image.offsets[p],
1685 .row_pitch = mapping->va_image.pitches[p],
1687 cl_image_desc image_desc;
1689 err = opencl_get_plane_format(src_fc->sw_format, p,
1690 mapping->va_image.width,
1691 mapping->va_image.height,
1695 av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from "
1696 "surface %#x) has invalid parameters: %d.\n",
1697 mapping->va_image.buf, surface_id, err);
1700 image_info.width = image_desc.image_width;
1701 image_info.height = image_desc.image_height;
1703 mapping->frame.planes[p] =
1704 priv->clCreateImageFromFdINTEL(dst_dev->context,
1706 if (!mapping->frame.planes[p]) {
1707 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
1708 "from plane %d of VA image %#x (derived from "
1709 "surface %#x): %d.\n", p,
1710 mapping->va_image.buf, surface_id, cle);
1715 dst->data[p] = (uint8_t*)mapping->frame.planes[p];
1718 err = ff_hwframe_map_create(src->hw_frames_ctx,
1719 dst, src, &opencl_unmap_from_vaapi,
1724 dst->width = src->width;
1725 dst->height = src->height;
1730 for (p = 0; p < mapping->frame.nb_planes; p++) {
1731 if (mapping->frame.planes[p])
1732 clReleaseMemObject(mapping->frame.planes[p]);
1734 vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf);
1736 vaDestroyImage(src_dev->display, mapping->va_image.image_id);
1744 static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
1746 if ((map_flags & AV_HWFRAME_MAP_READ) &&
1747 (map_flags & AV_HWFRAME_MAP_WRITE))
1748 return CL_MEM_READ_WRITE;
1749 else if (map_flags & AV_HWFRAME_MAP_READ)
1750 return CL_MEM_READ_ONLY;
1751 else if (map_flags & AV_HWFRAME_MAP_WRITE)
1752 return CL_MEM_WRITE_ONLY;
1757 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1759 static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
1760 HWMapDescriptor *hwmap)
1762 AVOpenCLFrameDescriptor *desc = hwmap->priv;
1763 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
1764 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
1769 av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
1771 cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
1772 frames_priv->command_queue, desc->nb_planes, desc->planes,
1774 if (cle != CL_SUCCESS) {
1775 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
1776 "handles: %d.\n", cle);
1779 opencl_wait_events(dst_fc, &event, 1);
1781 for (p = 0; p < desc->nb_planes; p++) {
1782 cle = clReleaseMemObject(desc->planes[p]);
1783 if (cle != CL_SUCCESS) {
1784 av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
1785 "image of plane %d of QSV/VAAPI surface: %d\n",
1793 static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
1794 const AVFrame *src, int flags)
1796 AVHWFramesContext *src_fc =
1797 (AVHWFramesContext*)src->hw_frames_ctx->data;
1798 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1799 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
1800 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
1801 AVOpenCLFrameDescriptor *desc;
1802 VASurfaceID va_surface;
1803 cl_mem_flags cl_flags;
1808 if (src->format == AV_PIX_FMT_QSV) {
1809 mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
1810 va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
1811 } else if (src->format == AV_PIX_FMT_VAAPI) {
1812 va_surface = (VASurfaceID)(uintptr_t)src->data[3];
1814 return AVERROR(ENOSYS);
1817 cl_flags = opencl_mem_flags_for_mapping(flags);
1819 return AVERROR(EINVAL);
1821 av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
1822 "OpenCL.\n", va_surface);
1824 desc = av_mallocz(sizeof(*desc));
1826 return AVERROR(ENOMEM);
1828 // The cl_intel_va_api_media_sharing extension only supports NV12
1829 // surfaces, so for now there are always exactly two planes.
1830 desc->nb_planes = 2;
1832 for (p = 0; p < desc->nb_planes; p++) {
1834 device_priv->clCreateFromVA_APIMediaSurfaceINTEL(
1835 dst_dev->context, cl_flags, &va_surface, p, &cle);
1836 if (!desc->planes[p]) {
1837 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
1838 "image from plane %d of QSV/VAAPI surface "
1839 "%#x: %d.\n", p, va_surface, cle);
1844 dst->data[p] = (uint8_t*)desc->planes[p];
1847 cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
1848 frames_priv->command_queue, desc->nb_planes, desc->planes,
1850 if (cle != CL_SUCCESS) {
1851 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
1852 "handles: %d.\n", cle);
1857 err = opencl_wait_events(dst_fc, &event, 1);
1861 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1862 &opencl_unmap_from_qsv, desc);
1866 dst->width = src->width;
1867 dst->height = src->height;
1872 for (p = 0; p < desc->nb_planes; p++)
1873 if (desc->planes[p])
1874 clReleaseMemObject(desc->planes[p]);
1881 static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1882 const AVFrame *src, int flags)
1884 av_assert0(src->format == AV_PIX_FMT_OPENCL);
1885 if (hwfc->sw_format != dst->format)
1886 return AVERROR(ENOSYS);
1887 return opencl_map_frame(hwfc, dst, src, flags);
1890 static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1891 const AVFrame *src, int flags)
1893 OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
1894 av_assert0(dst->format == AV_PIX_FMT_OPENCL);
1895 switch (src->format) {
1896 #if HAVE_OPENCL_VAAPI_BEIGNET
1897 case AV_PIX_FMT_VAAPI:
1898 if (priv->vaapi_mapping_usable)
1899 return opencl_map_from_vaapi(hwfc, dst, src, flags);
1901 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1902 case AV_PIX_FMT_QSV:
1903 case AV_PIX_FMT_VAAPI:
1904 if (priv->qsv_mapping_usable)
1905 return opencl_map_from_qsv(hwfc, dst, src, flags);
1908 return AVERROR(ENOSYS);
1911 static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
1912 AVHWFramesContext *src_fc, int flags)
1914 OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
1915 switch (src_fc->device_ctx->type) {
1916 #if HAVE_OPENCL_VAAPI_BEIGNET
1917 case AV_HWDEVICE_TYPE_VAAPI:
1918 if (!priv->vaapi_mapping_usable)
1919 return AVERROR(ENOSYS);
1922 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1923 case AV_HWDEVICE_TYPE_QSV:
1924 case AV_HWDEVICE_TYPE_VAAPI:
1925 if (!priv->qsv_mapping_usable)
1926 return AVERROR(ENOSYS);
1930 return AVERROR(ENOSYS);
1932 return opencl_frames_init_command_queue(dst_fc);
1935 const HWContextType ff_hwcontext_type_opencl = {
1936 .type = AV_HWDEVICE_TYPE_OPENCL,
1939 .device_hwctx_size = sizeof(AVOpenCLDeviceContext),
1940 .device_priv_size = sizeof(OpenCLDeviceContext),
1941 .frames_hwctx_size = sizeof(AVOpenCLFramesContext),
1942 .frames_priv_size = sizeof(OpenCLFramesContext),
1944 .device_create = &opencl_device_create,
1945 .device_derive = &opencl_device_derive,
1946 .device_init = &opencl_device_init,
1947 .device_uninit = &opencl_device_uninit,
1949 .frames_get_constraints = &opencl_frames_get_constraints,
1950 .frames_init = &opencl_frames_init,
1951 .frames_uninit = &opencl_frames_uninit,
1952 .frames_get_buffer = &opencl_get_buffer,
1954 .transfer_get_formats = &opencl_transfer_get_formats,
1955 .transfer_data_to = &opencl_transfer_data_to,
1956 .transfer_data_from = &opencl_transfer_data_from,
1958 .map_from = &opencl_map_from,
1959 .map_to = &opencl_map_to,
1960 .frames_derive_to = &opencl_frames_derive_to,
1962 .pix_fmts = (const enum AVPixelFormat[]) {