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
19 #define CL_USE_DEPRECATED_OPENCL_1_2_APIS
28 #include "hwcontext.h"
29 #include "hwcontext_internal.h"
30 #include "hwcontext_opencl.h"
34 #if HAVE_OPENCL_VAAPI_BEIGNET
37 #include <va/va_drmcommon.h>
38 #include <CL/cl_intel.h>
39 #include "hwcontext_vaapi.h"
42 #if HAVE_OPENCL_DRM_BEIGNET
44 #include <CL/cl_intel.h>
45 #include "hwcontext_drm.h"
48 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
49 #include <mfx/mfxstructures.h>
51 #include <CL/va_ext.h>
52 #include "hwcontext_vaapi.h"
57 #include <CL/cl_dx9_media_sharing.h>
59 #include "hwcontext_dxva2.h"
63 #include <CL/cl_d3d11.h>
64 #include "hwcontext_d3d11va.h"
67 #if HAVE_OPENCL_DRM_ARM
68 #include <CL/cl_ext.h>
69 #include <drm_fourcc.h>
70 #include "hwcontext_drm.h"
74 typedef struct OpenCLDeviceContext {
75 // Default command queue to use for transfer/mapping operations on
76 // the device. If the user supplies one, this is a reference to it.
77 // Otherwise, it is newly-created.
78 cl_command_queue command_queue;
80 // The platform the context exists on. This is needed to query and
81 // retrieve extension functions.
82 cl_platform_id platform_id;
84 // Platform/device-specific functions.
85 #if HAVE_OPENCL_DRM_BEIGNET
86 int beignet_drm_mapping_usable;
87 clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL;
90 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
91 int qsv_mapping_usable;
92 clCreateFromVA_APIMediaSurfaceINTEL_fn
93 clCreateFromVA_APIMediaSurfaceINTEL;
94 clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn
95 clEnqueueAcquireVA_APIMediaSurfacesINTEL;
96 clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn
97 clEnqueueReleaseVA_APIMediaSurfacesINTEL;
100 #if HAVE_OPENCL_DXVA2
101 int dxva2_mapping_usable;
102 cl_dx9_media_adapter_type_khr dx9_media_adapter_type;
104 clCreateFromDX9MediaSurfaceKHR_fn
105 clCreateFromDX9MediaSurfaceKHR;
106 clEnqueueAcquireDX9MediaSurfacesKHR_fn
107 clEnqueueAcquireDX9MediaSurfacesKHR;
108 clEnqueueReleaseDX9MediaSurfacesKHR_fn
109 clEnqueueReleaseDX9MediaSurfacesKHR;
112 #if HAVE_OPENCL_D3D11
113 int d3d11_mapping_usable;
114 clCreateFromD3D11Texture2DKHR_fn
115 clCreateFromD3D11Texture2DKHR;
116 clEnqueueAcquireD3D11ObjectsKHR_fn
117 clEnqueueAcquireD3D11ObjectsKHR;
118 clEnqueueReleaseD3D11ObjectsKHR_fn
119 clEnqueueReleaseD3D11ObjectsKHR;
122 #if HAVE_OPENCL_DRM_ARM
123 int drm_arm_mapping_usable;
125 } OpenCLDeviceContext;
127 typedef struct OpenCLFramesContext {
128 // Command queue used for transfer/mapping operations on this frames
129 // context. If the user supplies one, this is a reference to it.
130 // Otherwise, it is a reference to the default command queue for the
132 cl_command_queue command_queue;
134 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
135 // For mapping APIs which have separate creation and acquire/release
136 // steps, this stores the OpenCL memory objects corresponding to each
138 int nb_mapped_frames;
139 AVOpenCLFrameDescriptor *mapped_frames;
141 } OpenCLFramesContext;
144 static void opencl_error_callback(const char *errinfo,
145 const void *private_info, size_t cb,
148 AVHWDeviceContext *ctx = user_data;
149 av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo);
152 static void opencl_device_free(AVHWDeviceContext *hwdev)
154 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
157 cle = clReleaseContext(hwctx->context);
158 if (cle != CL_SUCCESS) {
159 av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL "
160 "context: %d.\n", cle);
166 cl_platform_info name;
167 } opencl_platform_params[] = {
168 { "platform_profile", CL_PLATFORM_PROFILE },
169 { "platform_version", CL_PLATFORM_VERSION },
170 { "platform_name", CL_PLATFORM_NAME },
171 { "platform_vendor", CL_PLATFORM_VENDOR },
172 { "platform_extensions", CL_PLATFORM_EXTENSIONS },
178 } opencl_device_params[] = {
179 { "device_name", CL_DEVICE_NAME },
180 { "device_vendor", CL_DEVICE_VENDOR },
181 { "driver_version", CL_DRIVER_VERSION },
182 { "device_version", CL_DEVICE_VERSION },
183 { "device_profile", CL_DEVICE_PROFILE },
184 { "device_extensions", CL_DEVICE_EXTENSIONS },
190 } opencl_device_types[] = {
191 { "cpu", CL_DEVICE_TYPE_CPU },
192 { "gpu", CL_DEVICE_TYPE_GPU },
193 { "accelerator", CL_DEVICE_TYPE_ACCELERATOR },
194 { "custom", CL_DEVICE_TYPE_CUSTOM },
195 { "default", CL_DEVICE_TYPE_DEFAULT },
196 { "all", CL_DEVICE_TYPE_ALL },
199 static char *opencl_get_platform_string(cl_platform_id platform_id,
200 cl_platform_info key)
205 cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size);
206 if (cle != CL_SUCCESS)
208 str = av_malloc(size);
211 cle = clGetPlatformInfo(platform_id, key, size, str, &size);
212 if (cle != CL_SUCCESS) {
216 av_assert0(strlen(str) + 1 == size);
220 static char *opencl_get_device_string(cl_device_id device_id,
226 cle = clGetDeviceInfo(device_id, key, 0, NULL, &size);
227 if (cle != CL_SUCCESS)
229 str = av_malloc(size);
232 cle = clGetDeviceInfo(device_id, key, size, str, &size);
233 if (cle != CL_SUCCESS) {
237 av_assert0(strlen(str) + 1== size);
241 static int opencl_check_platform_extension(cl_platform_id platform_id,
246 str = opencl_get_platform_string(platform_id,
247 CL_PLATFORM_EXTENSIONS);
248 if (str && strstr(str, name))
254 static int opencl_check_device_extension(cl_device_id device_id,
259 str = opencl_get_device_string(device_id,
260 CL_DEVICE_EXTENSIONS);
261 if (str && strstr(str, name))
267 static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev,
270 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
271 OpenCLDeviceContext *priv = hwdev->internal->priv;
273 if (opencl_check_platform_extension(priv->platform_id, name)) {
274 av_log(hwdev, AV_LOG_DEBUG,
275 "%s found as platform extension.\n", name);
279 if (opencl_check_device_extension(hwctx->device_id, name)) {
280 av_log(hwdev, AV_LOG_DEBUG,
281 "%s found as device extension.\n", name);
288 static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev,
289 cl_uint *nb_platforms,
290 cl_platform_id **platforms,
295 cle = clGetPlatformIDs(0, NULL, nb_platforms);
296 if (cle != CL_SUCCESS) {
297 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of "
298 "OpenCL platforms: %d.\n", cle);
299 return AVERROR(ENODEV);
301 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n",
304 *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms));
306 return AVERROR(ENOMEM);
308 cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL);
309 if (cle != CL_SUCCESS) {
310 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL "
311 "platforms: %d.\n", cle);
313 return AVERROR(ENODEV);
319 static int opencl_filter_platform(AVHWDeviceContext *hwdev,
320 cl_platform_id platform_id,
321 const char *platform_name,
324 AVDictionary *opts = context;
325 const AVDictionaryEntry *param;
329 for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) {
330 param = av_dict_get(opts, opencl_platform_params[i].key,
335 str = opencl_get_platform_string(platform_id,
336 opencl_platform_params[i].name);
338 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
339 "of platform \"%s\".\n",
340 opencl_platform_params[i].key, platform_name);
341 return AVERROR_UNKNOWN;
343 if (!av_stristr(str, param->value)) {
344 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
354 static int opencl_enumerate_devices(AVHWDeviceContext *hwdev,
355 cl_platform_id platform_id,
356 const char *platform_name,
358 cl_device_id **devices,
363 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
364 0, NULL, nb_devices);
365 if (cle == CL_DEVICE_NOT_FOUND) {
366 av_log(hwdev, AV_LOG_DEBUG, "No devices found "
367 "on platform \"%s\".\n", platform_name);
370 } else if (cle != CL_SUCCESS) {
371 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
372 "on platform \"%s\": %d.\n", platform_name, cle);
373 return AVERROR(ENODEV);
375 av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on "
376 "platform \"%s\".\n", *nb_devices, platform_name);
378 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
380 return AVERROR(ENOMEM);
382 cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL,
383 *nb_devices, *devices, NULL);
384 if (cle != CL_SUCCESS) {
385 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices "
386 "on platform \"%s\": %d.\n", platform_name, cle);
388 return AVERROR(ENODEV);
394 static int opencl_filter_device(AVHWDeviceContext *hwdev,
395 cl_device_id device_id,
396 const char *device_name,
399 AVDictionary *opts = context;
400 const AVDictionaryEntry *param;
404 param = av_dict_get(opts, "device_type", NULL, 0);
406 cl_device_type match_type = 0, device_type;
409 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) {
410 if (!strcmp(opencl_device_types[i].key, param->value)) {
411 match_type = opencl_device_types[i].type;
416 av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n",
418 return AVERROR(EINVAL);
421 cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
422 sizeof(device_type), &device_type, NULL);
423 if (cle != CL_SUCCESS) {
424 av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
425 "of device \"%s\".\n", device_name);
426 return AVERROR_UNKNOWN;
429 if (!(device_type & match_type)) {
430 av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n");
435 for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) {
436 param = av_dict_get(opts, opencl_device_params[i].key,
441 str = opencl_get_device_string(device_id,
442 opencl_device_params[i].name);
444 av_log(hwdev, AV_LOG_ERROR, "Failed to query %s "
445 "of device \"%s\".\n",
446 opencl_device_params[i].key, device_name);
447 return AVERROR_UNKNOWN;
449 if (!av_stristr(str, param->value)) {
450 av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n",
460 typedef struct OpenCLDeviceSelector {
464 int (*enumerate_platforms)(AVHWDeviceContext *hwdev,
465 cl_uint *nb_platforms,
466 cl_platform_id **platforms,
468 int (*filter_platform) (AVHWDeviceContext *hwdev,
469 cl_platform_id platform_id,
470 const char *platform_name,
472 int (*enumerate_devices) (AVHWDeviceContext *hwdev,
473 cl_platform_id platform_id,
474 const char *platform_name,
476 cl_device_id **devices,
478 int (*filter_device) (AVHWDeviceContext *hwdev,
479 cl_device_id device_id,
480 const char *device_name,
482 } OpenCLDeviceSelector;
484 static int opencl_device_create_internal(AVHWDeviceContext *hwdev,
485 const OpenCLDeviceSelector *selector,
486 cl_context_properties *props)
488 cl_uint nb_platforms;
489 cl_platform_id *platforms = NULL;
490 cl_platform_id platform_id;
492 cl_device_id *devices = NULL;
493 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
495 cl_context_properties default_props[3];
496 char *platform_name_src = NULL,
497 *device_name_src = NULL;
498 int err, found, p, d;
500 err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms,
506 for (p = 0; p < nb_platforms; p++) {
507 const char *platform_name;
509 if (selector->platform_index >= 0 &&
510 selector->platform_index != p)
513 av_freep(&platform_name_src);
514 platform_name_src = opencl_get_platform_string(platforms[p],
516 if (platform_name_src)
517 platform_name = platform_name_src;
519 platform_name = "Unknown Platform";
521 if (selector->filter_platform) {
522 err = selector->filter_platform(hwdev, platforms[p],
531 err = opencl_enumerate_devices(hwdev, platforms[p], platform_name,
532 &nb_devices, &devices,
537 for (d = 0; d < nb_devices; d++) {
538 const char *device_name;
540 if (selector->device_index >= 0 &&
541 selector->device_index != d)
544 av_freep(&device_name_src);
545 device_name_src = opencl_get_device_string(devices[d],
548 device_name = device_name_src;
550 device_name = "Unknown Device";
552 if (selector->filter_device) {
553 err = selector->filter_device(hwdev, devices[d],
562 av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d,
563 platform_name, device_name);
566 platform_id = platforms[p];
567 hwctx->device_id = devices[d];
574 av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n");
575 err = AVERROR(ENODEV);
579 av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n");
580 err = AVERROR(ENODEV);
585 props = default_props;
586 default_props[0] = CL_CONTEXT_PLATFORM;
587 default_props[1] = (intptr_t)platform_id;
588 default_props[2] = 0;
590 if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0)
591 props[1] = (intptr_t)platform_id;
594 hwctx->context = clCreateContext(props, 1, &hwctx->device_id,
595 &opencl_error_callback, hwdev, &cle);
596 if (!hwctx->context) {
597 av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: "
599 err = AVERROR(ENODEV);
603 hwdev->free = &opencl_device_free;
607 av_freep(&platform_name_src);
608 av_freep(&device_name_src);
609 av_freep(&platforms);
614 static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device,
615 AVDictionary *opts, int flags)
617 OpenCLDeviceSelector selector = {
619 .enumerate_platforms = &opencl_enumerate_platforms,
620 .filter_platform = &opencl_filter_platform,
621 .enumerate_devices = &opencl_enumerate_devices,
622 .filter_device = &opencl_filter_device,
625 if (device && device[0]) {
626 // Match one or both indices for platform and device.
627 int d = -1, p = -1, ret;
628 if (device[0] == '.')
629 ret = sscanf(device, ".%d", &d);
631 ret = sscanf(device, "%d.%d", &p, &d);
633 av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device "
634 "index specification \"%s\".\n", device);
635 return AVERROR(EINVAL);
637 selector.platform_index = p;
638 selector.device_index = d;
640 selector.platform_index = -1;
641 selector.device_index = -1;
644 return opencl_device_create_internal(hwdev, &selector, NULL);
647 static int opencl_device_init(AVHWDeviceContext *hwdev)
649 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
650 OpenCLDeviceContext *priv = hwdev->internal->priv;
653 if (hwctx->command_queue) {
654 cle = clRetainCommandQueue(hwctx->command_queue);
655 if (cle != CL_SUCCESS) {
656 av_log(hwdev, AV_LOG_ERROR, "Failed to retain external "
657 "command queue: %d.\n", cle);
660 priv->command_queue = hwctx->command_queue;
662 priv->command_queue = clCreateCommandQueue(hwctx->context,
665 if (!priv->command_queue) {
666 av_log(hwdev, AV_LOG_ERROR, "Failed to create internal "
667 "command queue: %d.\n", cle);
672 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM,
673 sizeof(priv->platform_id), &priv->platform_id,
675 if (cle != CL_SUCCESS) {
676 av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL "
677 "platform containing the device.\n");
681 #define CL_FUNC(name, desc) do { \
684 priv->name = clGetExtensionFunctionAddressForPlatform( \
685 priv->platform_id, #name); \
687 av_log(hwdev, AV_LOG_VERBOSE, \
688 desc " function not found (%s).\n", #name); \
691 av_log(hwdev, AV_LOG_VERBOSE, \
692 desc " function found (%s).\n", #name); \
696 #if HAVE_OPENCL_DRM_BEIGNET
700 CL_FUNC(clCreateImageFromFdINTEL,
701 "Beignet DRM to OpenCL image mapping");
704 av_log(hwdev, AV_LOG_WARNING, "Beignet DRM to OpenCL "
705 "mapping not usable.\n");
706 priv->beignet_drm_mapping_usable = 0;
708 priv->beignet_drm_mapping_usable = 1;
713 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
716 cl_context_properties *props = NULL;
717 VADisplay va_display;
718 const char *va_ext = "cl_intel_va_api_media_sharing";
721 if (!opencl_check_extension(hwdev, va_ext)) {
722 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
723 "required for QSV to OpenCL mapping.\n", va_ext);
727 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
728 0, NULL, &props_size);
729 if (cle != CL_SUCCESS) {
730 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
731 "properties: %d.\n", cle);
734 if (props_size == 0) {
735 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
736 "enabled on context creation to use QSV to "
737 "OpenCL mapping.\n");
741 props = av_malloc(props_size);
743 return AVERROR(ENOMEM);
745 cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES,
746 props_size, props, NULL);
747 if (cle != CL_SUCCESS) {
748 av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context "
749 "properties: %d.\n", cle);
754 for (i = 0; i < (props_size / sizeof(*props) - 1); i++) {
755 if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) {
756 va_display = (VADisplay)(intptr_t)props[i+1];
761 av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be "
762 "enabled on context creation to use QSV to "
763 "OpenCL mapping.\n");
766 if (!vaDisplayIsValid(va_display)) {
767 av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is "
768 "required on context creation to use QSV to "
769 "OpenCL mapping.\n");
773 CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL,
774 "Intel QSV to OpenCL mapping");
775 CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL,
776 "Intel QSV in OpenCL acquire");
777 CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL,
778 "Intel QSV in OpenCL release");
782 av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping "
784 priv->qsv_mapping_usable = 0;
786 priv->qsv_mapping_usable = 1;
792 #if HAVE_OPENCL_DXVA2
796 CL_FUNC(clCreateFromDX9MediaSurfaceKHR,
797 "DXVA2 to OpenCL mapping");
798 CL_FUNC(clEnqueueAcquireDX9MediaSurfacesKHR,
799 "DXVA2 in OpenCL acquire");
800 CL_FUNC(clEnqueueReleaseDX9MediaSurfacesKHR,
801 "DXVA2 in OpenCL release");
804 av_log(hwdev, AV_LOG_WARNING, "DXVA2 to OpenCL mapping "
806 priv->dxva2_mapping_usable = 0;
808 priv->dx9_media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
809 priv->dxva2_mapping_usable = 1;
814 #if HAVE_OPENCL_D3D11
816 const char *d3d11_ext = "cl_khr_d3d11_sharing";
817 const char *nv12_ext = "cl_intel_d3d11_nv12_media_sharing";
820 if (!opencl_check_extension(hwdev, d3d11_ext)) {
821 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
822 "required for D3D11 to OpenCL mapping.\n", d3d11_ext);
824 } else if (!opencl_check_extension(hwdev, nv12_ext)) {
825 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be "
826 "required for D3D11 to OpenCL mapping.\n", nv12_ext);
830 CL_FUNC(clCreateFromD3D11Texture2DKHR,
831 "D3D11 to OpenCL mapping");
832 CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR,
833 "D3D11 in OpenCL acquire");
834 CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR,
835 "D3D11 in OpenCL release");
838 av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping "
840 priv->d3d11_mapping_usable = 0;
842 priv->d3d11_mapping_usable = 1;
847 #if HAVE_OPENCL_DRM_ARM
849 const char *drm_arm_ext = "cl_arm_import_memory";
850 const char *image_ext = "cl_khr_image2d_from_buffer";
853 if (!opencl_check_extension(hwdev, drm_arm_ext)) {
854 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
855 "required for DRM to OpenCL mapping on ARM.\n",
859 if (!opencl_check_extension(hwdev, image_ext)) {
860 av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is "
861 "required for DRM to OpenCL mapping on ARM.\n",
866 // clImportMemoryARM() is linked statically.
869 av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM "
871 priv->drm_arm_mapping_usable = 0;
873 priv->drm_arm_mapping_usable = 1;
883 static void opencl_device_uninit(AVHWDeviceContext *hwdev)
885 OpenCLDeviceContext *priv = hwdev->internal->priv;
888 if (priv->command_queue) {
889 cle = clReleaseCommandQueue(priv->command_queue);
890 if (cle != CL_SUCCESS) {
891 av_log(hwdev, AV_LOG_ERROR, "Failed to release internal "
892 "command queue reference: %d.\n", cle);
894 priv->command_queue = NULL;
898 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
899 static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev,
900 cl_platform_id platform_id,
901 const char *platform_name,
904 // This doesn't exist as a platform extension, so just test whether
905 // the function we will use for device enumeration exists.
907 if (!clGetExtensionFunctionAddressForPlatform(platform_id,
908 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) {
909 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the "
910 "VAAPI device enumeration function.\n", platform_name);
917 static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev,
918 cl_platform_id platform_id,
919 const char *platform_name,
921 cl_device_id **devices,
924 VADisplay va_display = context;
925 clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn
926 clGetDeviceIDsFromVA_APIMediaAdapterINTEL;
930 clGetDeviceIDsFromVA_APIMediaAdapterINTEL =
931 clGetExtensionFunctionAddressForPlatform(platform_id,
932 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL");
933 if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) {
934 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
935 "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n");
936 return AVERROR_UNKNOWN;
939 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
940 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
941 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices);
942 if (cle == CL_DEVICE_NOT_FOUND) {
943 av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found "
944 "on platform \"%s\".\n", platform_name);
947 } else if (cle != CL_SUCCESS) {
948 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
949 "on platform \"%s\": %d.\n", platform_name, cle);
950 return AVERROR_UNKNOWN;
953 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
955 return AVERROR(ENOMEM);
957 cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL(
958 platform_id, CL_VA_API_DISPLAY_INTEL, va_display,
959 CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL);
960 if (cle != CL_SUCCESS) {
961 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting "
962 "devices on platform \"%s\": %d.\n", platform_name, cle);
964 return AVERROR_UNKNOWN;
970 static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev,
971 cl_device_id device_id,
972 const char *device_name,
975 const char *va_ext = "cl_intel_va_api_media_sharing";
977 if (opencl_check_device_extension(device_id, va_ext)) {
980 av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
981 "%s extension.\n", device_name, va_ext);
987 #if HAVE_OPENCL_DXVA2
988 static int opencl_filter_dxva2_platform(AVHWDeviceContext *hwdev,
989 cl_platform_id platform_id,
990 const char *platform_name,
993 const char *dx9_ext = "cl_khr_dx9_media_sharing";
995 if (opencl_check_platform_extension(platform_id, dx9_ext)) {
998 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
999 "%s extension.\n", platform_name, dx9_ext);
1004 static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev,
1005 cl_platform_id platform_id,
1006 const char *platform_name,
1007 cl_uint *nb_devices,
1008 cl_device_id **devices,
1011 IDirect3DDevice9 *device = context;
1012 clGetDeviceIDsFromDX9MediaAdapterKHR_fn
1013 clGetDeviceIDsFromDX9MediaAdapterKHR;
1014 cl_dx9_media_adapter_type_khr media_adapter_type = CL_ADAPTER_D3D9EX_KHR;
1017 clGetDeviceIDsFromDX9MediaAdapterKHR =
1018 clGetExtensionFunctionAddressForPlatform(platform_id,
1019 "clGetDeviceIDsFromDX9MediaAdapterKHR");
1020 if (!clGetDeviceIDsFromDX9MediaAdapterKHR) {
1021 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
1022 "clGetDeviceIDsFromDX9MediaAdapterKHR().\n");
1023 return AVERROR_UNKNOWN;
1026 cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
1027 platform_id, 1, &media_adapter_type, (void**)&device,
1028 CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
1029 0, NULL, nb_devices);
1030 if (cle == CL_DEVICE_NOT_FOUND) {
1031 av_log(hwdev, AV_LOG_DEBUG, "No DXVA2-supporting devices found "
1032 "on platform \"%s\".\n", platform_name);
1035 } else if (cle != CL_SUCCESS) {
1036 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
1037 "on platform \"%s\": %d.\n", platform_name, cle);
1038 return AVERROR_UNKNOWN;
1041 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
1043 return AVERROR(ENOMEM);
1045 cle = clGetDeviceIDsFromDX9MediaAdapterKHR(
1046 platform_id, 1, &media_adapter_type, (void**)&device,
1047 CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR,
1048 *nb_devices, *devices, NULL);
1049 if (cle != CL_SUCCESS) {
1050 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of DXVA2-supporting "
1051 "devices on platform \"%s\": %d.\n", platform_name, cle);
1053 return AVERROR_UNKNOWN;
1060 #if HAVE_OPENCL_D3D11
1061 static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev,
1062 cl_platform_id platform_id,
1063 const char *platform_name,
1066 const char *d3d11_ext = "cl_khr_d3d11_sharing";
1068 if (opencl_check_platform_extension(platform_id, d3d11_ext)) {
1071 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
1072 "%s extension.\n", platform_name, d3d11_ext);
1077 static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev,
1078 cl_platform_id platform_id,
1079 const char *platform_name,
1080 cl_uint *nb_devices,
1081 cl_device_id **devices,
1084 ID3D11Device *device = context;
1085 clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR;
1088 clGetDeviceIDsFromD3D11KHR =
1089 clGetExtensionFunctionAddressForPlatform(platform_id,
1090 "clGetDeviceIDsFromD3D11KHR");
1091 if (!clGetDeviceIDsFromD3D11KHR) {
1092 av_log(hwdev, AV_LOG_ERROR, "Failed to get address of "
1093 "clGetDeviceIDsFromD3D11KHR().\n");
1094 return AVERROR_UNKNOWN;
1097 cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1098 CL_D3D11_DEVICE_KHR, device,
1099 CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1100 0, NULL, nb_devices);
1101 if (cle == CL_DEVICE_NOT_FOUND) {
1102 av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found "
1103 "on platform \"%s\".\n", platform_name);
1106 } else if (cle != CL_SUCCESS) {
1107 av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices "
1108 "on platform \"%s\": %d.\n", platform_name, cle);
1109 return AVERROR_UNKNOWN;
1112 *devices = av_malloc_array(*nb_devices, sizeof(**devices));
1114 return AVERROR(ENOMEM);
1116 cle = clGetDeviceIDsFromD3D11KHR(platform_id,
1117 CL_D3D11_DEVICE_KHR, device,
1118 CL_PREFERRED_DEVICES_FOR_D3D11_KHR,
1119 *nb_devices, *devices, NULL);
1120 if (cle != CL_SUCCESS) {
1121 av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting "
1122 "devices on platform \"%s\": %d.\n", platform_name, cle);
1124 return AVERROR_UNKNOWN;
1131 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
1132 static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev,
1133 cl_device_id device_id,
1134 const char *device_name,
1137 cl_device_type device_type;
1140 cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE,
1141 sizeof(device_type), &device_type, NULL);
1142 if (cle != CL_SUCCESS) {
1143 av_log(hwdev, AV_LOG_ERROR, "Failed to query device type "
1144 "of device \"%s\".\n", device_name);
1145 return AVERROR_UNKNOWN;
1147 if (!(device_type & CL_DEVICE_TYPE_GPU)) {
1148 av_log(hwdev, AV_LOG_DEBUG, "Device %s skipped (not GPU).\n",
1157 #if HAVE_OPENCL_DRM_ARM
1158 static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev,
1159 cl_platform_id platform_id,
1160 const char *platform_name,
1163 const char *drm_arm_ext = "cl_arm_import_memory";
1165 if (opencl_check_platform_extension(platform_id, drm_arm_ext)) {
1168 av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the "
1169 "%s extension.\n", platform_name, drm_arm_ext);
1174 static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev,
1175 cl_device_id device_id,
1176 const char *device_name,
1179 const char *drm_arm_ext = "cl_arm_import_memory";
1181 if (opencl_check_device_extension(device_id, drm_arm_ext)) {
1184 av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the "
1185 "%s extension.\n", device_name, drm_arm_ext);
1191 static int opencl_device_derive(AVHWDeviceContext *hwdev,
1192 AVHWDeviceContext *src_ctx,
1196 switch (src_ctx->type) {
1198 #if HAVE_OPENCL_DRM_BEIGNET
1199 case AV_HWDEVICE_TYPE_DRM:
1200 case AV_HWDEVICE_TYPE_VAAPI:
1202 // Surface mapping works via DRM PRIME fds with no special
1203 // initialisation required in advance. This just finds the
1204 // Beignet ICD by name.
1205 AVDictionary *opts = NULL;
1207 err = av_dict_set(&opts, "platform_vendor", "Intel", 0);
1209 err = av_dict_set(&opts, "platform_version", "beignet", 0);
1211 OpenCLDeviceSelector selector = {
1212 .platform_index = -1,
1215 .enumerate_platforms = &opencl_enumerate_platforms,
1216 .filter_platform = &opencl_filter_platform,
1217 .enumerate_devices = &opencl_enumerate_devices,
1218 .filter_device = NULL,
1220 err = opencl_device_create_internal(hwdev, &selector, NULL);
1222 av_dict_free(&opts);
1227 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
1228 // The generic code automatically attempts to derive from all
1229 // ancestors of the given device, so we can ignore QSV devices here
1230 // and just consider the inner VAAPI device it was derived from.
1231 case AV_HWDEVICE_TYPE_VAAPI:
1233 AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx;
1234 cl_context_properties props[7] = {
1235 CL_CONTEXT_PLATFORM,
1237 CL_CONTEXT_VA_API_DISPLAY_INTEL,
1238 (intptr_t)src_hwctx->display,
1239 CL_CONTEXT_INTEROP_USER_SYNC,
1243 OpenCLDeviceSelector selector = {
1244 .platform_index = -1,
1246 .context = src_hwctx->display,
1247 .enumerate_platforms = &opencl_enumerate_platforms,
1248 .filter_platform = &opencl_filter_intel_media_vaapi_platform,
1249 .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices,
1250 .filter_device = &opencl_filter_intel_media_vaapi_device,
1253 err = opencl_device_create_internal(hwdev, &selector, props);
1258 #if HAVE_OPENCL_DXVA2
1259 case AV_HWDEVICE_TYPE_DXVA2:
1261 AVDXVA2DeviceContext *src_hwctx = src_ctx->hwctx;
1262 IDirect3DDevice9 *device;
1263 HANDLE device_handle;
1266 hr = IDirect3DDeviceManager9_OpenDeviceHandle(src_hwctx->devmgr,
1269 av_log(hwdev, AV_LOG_ERROR, "Failed to open device handle "
1270 "for Direct3D9 device: %lx.\n", (unsigned long)hr);
1271 err = AVERROR_UNKNOWN;
1275 hr = IDirect3DDeviceManager9_LockDevice(src_hwctx->devmgr,
1278 if (SUCCEEDED(hr)) {
1279 cl_context_properties props[5] = {
1280 CL_CONTEXT_PLATFORM,
1282 CL_CONTEXT_ADAPTER_D3D9EX_KHR,
1286 OpenCLDeviceSelector selector = {
1287 .platform_index = -1,
1290 .enumerate_platforms = &opencl_enumerate_platforms,
1291 .filter_platform = &opencl_filter_dxva2_platform,
1292 .enumerate_devices = &opencl_enumerate_dxva2_devices,
1293 .filter_device = &opencl_filter_gpu_device,
1296 err = opencl_device_create_internal(hwdev, &selector, props);
1298 IDirect3DDeviceManager9_UnlockDevice(src_hwctx->devmgr,
1299 device_handle, FALSE);
1301 av_log(hwdev, AV_LOG_ERROR, "Failed to lock device handle "
1302 "for Direct3D9 device: %lx.\n", (unsigned long)hr);
1303 err = AVERROR_UNKNOWN;
1306 IDirect3DDeviceManager9_CloseDeviceHandle(src_hwctx->devmgr,
1312 #if HAVE_OPENCL_D3D11
1313 case AV_HWDEVICE_TYPE_D3D11VA:
1315 AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx;
1316 cl_context_properties props[5] = {
1317 CL_CONTEXT_PLATFORM,
1319 CL_CONTEXT_D3D11_DEVICE_KHR,
1320 (intptr_t)src_hwctx->device,
1323 OpenCLDeviceSelector selector = {
1324 .platform_index = -1,
1326 .context = src_hwctx->device,
1327 .enumerate_platforms = &opencl_enumerate_platforms,
1328 .filter_platform = &opencl_filter_d3d11_platform,
1329 .enumerate_devices = &opencl_enumerate_d3d11_devices,
1330 .filter_device = &opencl_filter_gpu_device,
1333 err = opencl_device_create_internal(hwdev, &selector, props);
1338 #if HAVE_OPENCL_DRM_ARM
1339 case AV_HWDEVICE_TYPE_DRM:
1341 OpenCLDeviceSelector selector = {
1342 .platform_index = -1,
1345 .enumerate_platforms = &opencl_enumerate_platforms,
1346 .filter_platform = &opencl_filter_drm_arm_platform,
1347 .enumerate_devices = &opencl_enumerate_devices,
1348 .filter_device = &opencl_filter_drm_arm_device,
1351 err = opencl_device_create_internal(hwdev, &selector, NULL);
1357 err = AVERROR(ENOSYS);
1364 return opencl_device_init(hwdev);
1367 static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
1368 int plane, int width, int height,
1369 cl_image_format *image_format,
1370 cl_image_desc *image_desc)
1372 const AVPixFmtDescriptor *desc;
1373 const AVComponentDescriptor *comp;
1374 int channels = 0, order = 0, depth = 0, step = 0;
1375 int wsub, hsub, alpha;
1378 if (plane >= AV_NUM_DATA_POINTERS)
1379 return AVERROR(ENOENT);
1381 desc = av_pix_fmt_desc_get(pixfmt);
1383 // Only normal images are allowed.
1384 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM |
1385 AV_PIX_FMT_FLAG_HWACCEL |
1386 AV_PIX_FMT_FLAG_PAL))
1387 return AVERROR(EINVAL);
1389 wsub = 1 << desc->log2_chroma_w;
1390 hsub = 1 << desc->log2_chroma_h;
1391 // Subsampled components must be exact.
1392 if (width & wsub - 1 || height & hsub - 1)
1393 return AVERROR(EINVAL);
1395 for (c = 0; c < desc->nb_components; c++) {
1396 comp = &desc->comp[c];
1397 if (comp->plane != plane)
1399 // The step size must be a power of two.
1400 if (comp->step != 1 && comp->step != 2 &&
1401 comp->step != 4 && comp->step != 8)
1402 return AVERROR(EINVAL);
1403 // The bits in each component must be packed in the
1404 // most-significant-bits of the relevant bytes.
1405 if (comp->shift + comp->depth != 8 &&
1406 comp->shift + comp->depth != 16)
1407 return AVERROR(EINVAL);
1408 // The depth must not vary between components.
1409 if (depth && comp->depth != depth)
1410 return AVERROR(EINVAL);
1411 // If a single data element crosses multiple bytes then
1412 // it must match the native endianness.
1413 if (comp->depth > 8 &&
1414 HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE))
1415 return AVERROR(EINVAL);
1416 // A single data element must not contain multiple samples
1417 // from the same component.
1418 if (step && comp->step != step)
1419 return AVERROR(EINVAL);
1420 order = order * 10 + c + 1;
1421 depth = comp->depth;
1423 alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
1424 c == desc->nb_components - 1);
1428 return AVERROR(ENOENT);
1430 memset(image_format, 0, sizeof(*image_format));
1431 memset(image_desc, 0, sizeof(*image_desc));
1432 image_desc->image_type = CL_MEM_OBJECT_IMAGE2D;
1434 if (plane == 0 || alpha) {
1435 image_desc->image_width = width;
1436 image_desc->image_height = height;
1437 image_desc->image_row_pitch = step * width;
1439 image_desc->image_width = width / wsub;
1440 image_desc->image_height = height / hsub;
1441 image_desc->image_row_pitch = step * width / wsub;
1445 image_format->image_channel_data_type = CL_UNORM_INT8;
1448 image_format->image_channel_data_type = CL_UNORM_INT16;
1450 return AVERROR(EINVAL);
1453 #define CHANNEL_ORDER(order, type) \
1454 case order: image_format->image_channel_order = type; break;
1456 CHANNEL_ORDER(1, CL_R);
1457 CHANNEL_ORDER(2, CL_R);
1458 CHANNEL_ORDER(3, CL_R);
1459 CHANNEL_ORDER(4, CL_R);
1460 CHANNEL_ORDER(12, CL_RG);
1461 CHANNEL_ORDER(23, CL_RG);
1462 CHANNEL_ORDER(1234, CL_RGBA);
1463 CHANNEL_ORDER(3214, CL_BGRA);
1464 CHANNEL_ORDER(4123, CL_ARGB);
1466 CHANNEL_ORDER(4321, CL_ABGR);
1469 return AVERROR(EINVAL);
1471 #undef CHANNEL_ORDER
1476 static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev,
1477 const void *hwconfig,
1478 AVHWFramesConstraints *constraints)
1480 AVOpenCLDeviceContext *hwctx = hwdev->hwctx;
1481 cl_uint nb_image_formats;
1482 cl_image_format *image_formats = NULL;
1484 enum AVPixelFormat pix_fmt;
1485 int err, pix_fmts_found;
1486 size_t max_width, max_height;
1488 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH,
1489 sizeof(max_width), &max_width, NULL);
1490 if (cle != CL_SUCCESS) {
1491 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1492 "supported image width: %d.\n", cle);
1494 constraints->max_width = max_width;
1496 cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT,
1497 sizeof(max_height), &max_height, NULL);
1498 if (cle != CL_SUCCESS) {
1499 av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum "
1500 "supported image height: %d.\n", cle);
1502 constraints->max_height = max_height;
1504 av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n",
1505 constraints->max_width, constraints->max_height);
1507 cle = clGetSupportedImageFormats(hwctx->context,
1509 CL_MEM_OBJECT_IMAGE2D,
1510 0, NULL, &nb_image_formats);
1511 if (cle != CL_SUCCESS) {
1512 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1513 "image formats: %d.\n", cle);
1514 err = AVERROR(ENOSYS);
1517 if (nb_image_formats == 0) {
1518 av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL "
1519 "driver (zero supported image formats).\n");
1520 err = AVERROR(ENOSYS);
1525 av_malloc_array(nb_image_formats, sizeof(*image_formats));
1526 if (!image_formats) {
1527 err = AVERROR(ENOMEM);
1531 cle = clGetSupportedImageFormats(hwctx->context,
1533 CL_MEM_OBJECT_IMAGE2D,
1535 image_formats, NULL);
1536 if (cle != CL_SUCCESS) {
1537 av_log(hwdev, AV_LOG_ERROR, "Failed to query supported "
1538 "image formats: %d.\n", cle);
1539 err = AVERROR(ENOSYS);
1544 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
1545 cl_image_format image_format;
1546 cl_image_desc image_desc;
1549 for (plane = 0;; plane++) {
1550 err = opencl_get_plane_format(pix_fmt, plane, 0, 0,
1556 for (i = 0; i < nb_image_formats; i++) {
1557 if (image_formats[i].image_channel_order ==
1558 image_format.image_channel_order &&
1559 image_formats[i].image_channel_data_type ==
1560 image_format.image_channel_data_type)
1563 if (i == nb_image_formats) {
1564 err = AVERROR(EINVAL);
1568 if (err != AVERROR(ENOENT))
1571 av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n",
1572 av_get_pix_fmt_name(pix_fmt));
1574 err = av_reallocp_array(&constraints->valid_sw_formats,
1576 sizeof(*constraints->valid_sw_formats));
1579 constraints->valid_sw_formats[pix_fmts_found] = pix_fmt;
1580 constraints->valid_sw_formats[pix_fmts_found + 1] =
1585 av_freep(&image_formats);
1587 constraints->valid_hw_formats =
1588 av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
1589 if (!constraints->valid_hw_formats) {
1590 err = AVERROR(ENOMEM);
1593 constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL;
1594 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
1599 av_freep(&image_formats);
1603 static void opencl_pool_free(void *opaque, uint8_t *data)
1605 AVHWFramesContext *hwfc = opaque;
1606 AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data;
1610 for (p = 0; p < desc->nb_planes; p++) {
1611 cle = clReleaseMemObject(desc->planes[p]);
1612 if (cle != CL_SUCCESS) {
1613 av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: "
1621 static AVBufferRef *opencl_pool_alloc(void *opaque, int size)
1623 AVHWFramesContext *hwfc = opaque;
1624 AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1625 AVOpenCLFrameDescriptor *desc;
1628 cl_image_format image_format;
1629 cl_image_desc image_desc;
1633 desc = av_mallocz(sizeof(*desc));
1638 err = opencl_get_plane_format(hwfc->sw_format, p,
1639 hwfc->width, hwfc->height,
1640 &image_format, &image_desc);
1641 if (err == AVERROR(ENOENT))
1646 // For generic image objects, the pitch is determined by the
1648 image_desc.image_row_pitch = 0;
1650 image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE,
1651 &image_format, &image_desc, NULL, &cle);
1653 av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
1654 "plane %d: %d.\n", p, cle);
1658 desc->planes[p] = image;
1661 desc->nb_planes = p;
1663 ref = av_buffer_create((uint8_t*)desc, sizeof(*desc),
1664 &opencl_pool_free, hwfc, 0);
1671 for (p = 0; desc->planes[p]; p++)
1672 clReleaseMemObject(desc->planes[p]);
1677 static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc)
1679 AVOpenCLFramesContext *hwctx = hwfc->hwctx;
1680 OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv;
1681 OpenCLFramesContext *priv = hwfc->internal->priv;
1684 priv->command_queue = hwctx->command_queue ? hwctx->command_queue
1685 : devpriv->command_queue;
1686 cle = clRetainCommandQueue(priv->command_queue);
1687 if (cle != CL_SUCCESS) {
1688 av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame "
1689 "command queue: %d.\n", cle);
1690 return AVERROR(EIO);
1696 static int opencl_frames_init(AVHWFramesContext *hwfc)
1699 hwfc->internal->pool_internal =
1700 av_buffer_pool_init2(sizeof(cl_mem), hwfc,
1701 &opencl_pool_alloc, NULL);
1702 if (!hwfc->internal->pool_internal)
1703 return AVERROR(ENOMEM);
1706 return opencl_frames_init_command_queue(hwfc);
1709 static void opencl_frames_uninit(AVHWFramesContext *hwfc)
1711 OpenCLFramesContext *priv = hwfc->internal->priv;
1714 #if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11
1716 for (i = 0; i < priv->nb_mapped_frames; i++) {
1717 AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i];
1718 for (p = 0; p < desc->nb_planes; p++) {
1719 cle = clReleaseMemObject(desc->planes[p]);
1720 if (cle != CL_SUCCESS) {
1721 av_log(hwfc, AV_LOG_ERROR, "Failed to release mapped "
1722 "frame object (frame %d plane %d): %d.\n",
1727 av_freep(&priv->mapped_frames);
1730 cle = clReleaseCommandQueue(priv->command_queue);
1731 if (cle != CL_SUCCESS) {
1732 av_log(hwfc, AV_LOG_ERROR, "Failed to release frame "
1733 "command queue: %d.\n", cle);
1737 static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
1739 AVOpenCLFrameDescriptor *desc;
1742 frame->buf[0] = av_buffer_pool_get(hwfc->pool);
1744 return AVERROR(ENOMEM);
1746 desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data;
1748 for (p = 0; p < desc->nb_planes; p++)
1749 frame->data[p] = (uint8_t*)desc->planes[p];
1751 frame->format = AV_PIX_FMT_OPENCL;
1752 frame->width = hwfc->width;
1753 frame->height = hwfc->height;
1758 static int opencl_transfer_get_formats(AVHWFramesContext *hwfc,
1759 enum AVHWFrameTransferDirection dir,
1760 enum AVPixelFormat **formats)
1762 enum AVPixelFormat *fmts;
1764 fmts = av_malloc_array(2, sizeof(*fmts));
1766 return AVERROR(ENOMEM);
1768 fmts[0] = hwfc->sw_format;
1769 fmts[1] = AV_PIX_FMT_NONE;
1775 static int opencl_wait_events(AVHWFramesContext *hwfc,
1776 cl_event *events, int nb_events)
1781 cle = clWaitForEvents(nb_events, events);
1782 if (cle != CL_SUCCESS) {
1783 av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event "
1784 "completion: %d.\n", cle);
1785 return AVERROR(EIO);
1788 for (i = 0; i < nb_events; i++) {
1789 cle = clReleaseEvent(events[i]);
1790 if (cle != CL_SUCCESS) {
1791 av_log(hwfc, AV_LOG_ERROR, "Failed to release "
1792 "event: %d.\n", cle);
1799 static int opencl_transfer_data_from(AVHWFramesContext *hwfc,
1800 AVFrame *dst, const AVFrame *src)
1802 OpenCLFramesContext *priv = hwfc->internal->priv;
1803 cl_image_format image_format;
1804 cl_image_desc image_desc;
1806 size_t origin[3] = { 0, 0, 0 };
1808 cl_event events[AV_NUM_DATA_POINTERS];
1811 if (dst->format != hwfc->sw_format)
1812 return AVERROR(EINVAL);
1815 err = opencl_get_plane_format(hwfc->sw_format, p,
1816 src->width, src->height,
1817 &image_format, &image_desc);
1819 if (err == AVERROR(ENOENT))
1824 if (!dst->data[p]) {
1825 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1826 "destination frame for transfer.\n", p);
1827 err = AVERROR(EINVAL);
1831 region[0] = image_desc.image_width;
1832 region[1] = image_desc.image_height;
1835 cle = clEnqueueReadImage(priv->command_queue,
1836 (cl_mem)src->data[p],
1837 CL_FALSE, origin, region,
1838 dst->linesize[p], 0,
1840 0, NULL, &events[p]);
1841 if (cle != CL_SUCCESS) {
1842 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of "
1843 "OpenCL image plane %d: %d.\n", p, cle);
1849 opencl_wait_events(hwfc, events, p);
1854 static int opencl_transfer_data_to(AVHWFramesContext *hwfc,
1855 AVFrame *dst, const AVFrame *src)
1857 OpenCLFramesContext *priv = hwfc->internal->priv;
1858 cl_image_format image_format;
1859 cl_image_desc image_desc;
1861 size_t origin[3] = { 0, 0, 0 };
1863 cl_event events[AV_NUM_DATA_POINTERS];
1866 if (src->format != hwfc->sw_format)
1867 return AVERROR(EINVAL);
1870 err = opencl_get_plane_format(hwfc->sw_format, p,
1871 src->width, src->height,
1872 &image_format, &image_desc);
1874 if (err == AVERROR(ENOENT))
1879 if (!src->data[p]) {
1880 av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on "
1881 "source frame for transfer.\n", p);
1882 err = AVERROR(EINVAL);
1886 region[0] = image_desc.image_width;
1887 region[1] = image_desc.image_height;
1890 cle = clEnqueueWriteImage(priv->command_queue,
1891 (cl_mem)dst->data[p],
1892 CL_FALSE, origin, region,
1893 src->linesize[p], 0,
1895 0, NULL, &events[p]);
1896 if (cle != CL_SUCCESS) {
1897 av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of "
1898 "OpenCL image plane %d: %d.\n", p, cle);
1904 opencl_wait_events(hwfc, events, p);
1909 typedef struct OpenCLMapping {
1910 // The mapped addresses for each plane.
1911 // The destination frame is not available when we unmap, so these
1912 // need to be stored separately.
1913 void *address[AV_NUM_DATA_POINTERS];
1916 static void opencl_unmap_frame(AVHWFramesContext *hwfc,
1917 HWMapDescriptor *hwmap)
1919 OpenCLFramesContext *priv = hwfc->internal->priv;
1920 OpenCLMapping *map = hwmap->priv;
1921 cl_event events[AV_NUM_DATA_POINTERS];
1925 for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) {
1926 if (!map->address[p])
1929 cle = clEnqueueUnmapMemObject(priv->command_queue,
1930 (cl_mem)hwmap->source->data[p],
1932 0, NULL, &events[e]);
1933 if (cle != CL_SUCCESS) {
1934 av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL "
1935 "image plane %d: %d.\n", p, cle);
1940 opencl_wait_events(hwfc, events, e);
1945 static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst,
1946 const AVFrame *src, int flags)
1948 OpenCLFramesContext *priv = hwfc->internal->priv;
1949 cl_map_flags map_flags;
1950 cl_image_format image_format;
1951 cl_image_desc image_desc;
1954 size_t origin[3] = { 0, 0, 0 };
1957 cl_event events[AV_NUM_DATA_POINTERS];
1960 av_assert0(hwfc->sw_format == dst->format);
1962 if (flags & AV_HWFRAME_MAP_OVERWRITE &&
1963 !(flags & AV_HWFRAME_MAP_READ)) {
1964 // This is mutually exclusive with the read/write flags, so
1965 // there is no way to map with read here.
1966 map_flags = CL_MAP_WRITE_INVALIDATE_REGION;
1969 if (flags & AV_HWFRAME_MAP_READ)
1970 map_flags |= CL_MAP_READ;
1971 if (flags & AV_HWFRAME_MAP_WRITE)
1972 map_flags |= CL_MAP_WRITE;
1975 map = av_mallocz(sizeof(*map));
1977 return AVERROR(ENOMEM);
1980 err = opencl_get_plane_format(hwfc->sw_format, p,
1981 src->width, src->height,
1982 &image_format, &image_desc);
1983 if (err == AVERROR(ENOENT))
1988 region[0] = image_desc.image_width;
1989 region[1] = image_desc.image_height;
1993 clEnqueueMapImage(priv->command_queue,
1994 (cl_mem)src->data[p],
1995 CL_FALSE, map_flags, origin, region,
1996 &row_pitch, NULL, 0, NULL,
1998 if (!map->address[p]) {
1999 av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL "
2000 "image plane %d: %d.\n", p, cle);
2005 dst->data[p] = map->address[p];
2007 av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n",
2008 p, src->data[p], dst->data[p]);
2011 err = opencl_wait_events(hwfc, events, p);
2015 err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
2016 &opencl_unmap_frame, map);
2020 dst->width = src->width;
2021 dst->height = src->height;
2026 for (p = 0; p < AV_NUM_DATA_POINTERS; p++) {
2027 if (!map->address[p])
2029 clEnqueueUnmapMemObject(priv->command_queue,
2030 (cl_mem)src->data[p],
2032 0, NULL, &events[p]);
2035 opencl_wait_events(hwfc, events, p);
2040 #if HAVE_OPENCL_DRM_BEIGNET
2042 typedef struct DRMBeignetToOpenCLMapping {
2044 AVDRMFrameDescriptor *drm_desc;
2046 AVOpenCLFrameDescriptor frame;
2047 } DRMBeignetToOpenCLMapping;
2049 static void opencl_unmap_from_drm_beignet(AVHWFramesContext *dst_fc,
2050 HWMapDescriptor *hwmap)
2052 DRMBeignetToOpenCLMapping *mapping = hwmap->priv;
2056 for (i = 0; i < mapping->frame.nb_planes; i++) {
2057 cle = clReleaseMemObject(mapping->frame.planes[i]);
2058 if (cle != CL_SUCCESS) {
2059 av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL image "
2060 "of plane %d of DRM frame: %d.\n", i, cle);
2067 static int opencl_map_from_drm_beignet(AVHWFramesContext *dst_fc,
2068 AVFrame *dst, const AVFrame *src,
2071 AVOpenCLDeviceContext *hwctx = dst_fc->device_ctx->hwctx;
2072 OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
2073 DRMBeignetToOpenCLMapping *mapping;
2074 const AVDRMFrameDescriptor *desc;
2078 desc = (const AVDRMFrameDescriptor*)src->data[0];
2080 mapping = av_mallocz(sizeof(*mapping));
2082 return AVERROR(ENOMEM);
2085 for (i = 0; i < desc->nb_layers; i++) {
2086 const AVDRMLayerDescriptor *layer = &desc->layers[i];
2087 for (j = 0; j < layer->nb_planes; j++) {
2088 const AVDRMPlaneDescriptor *plane = &layer->planes[j];
2089 const AVDRMObjectDescriptor *object =
2090 &desc->objects[plane->object_index];
2092 cl_import_image_info_intel image_info = {
2094 .size = object->size,
2095 .type = CL_MEM_OBJECT_IMAGE2D,
2096 .offset = plane->offset,
2097 .row_pitch = plane->pitch,
2099 cl_image_desc image_desc;
2101 err = opencl_get_plane_format(dst_fc->sw_format, p,
2102 src->width, src->height,
2106 av_log(dst_fc, AV_LOG_ERROR, "DRM frame layer %d "
2107 "plane %d is not representable in OpenCL: %d.\n",
2111 image_info.width = image_desc.image_width;
2112 image_info.height = image_desc.image_height;
2114 mapping->frame.planes[p] =
2115 priv->clCreateImageFromFdINTEL(hwctx->context,
2117 if (!mapping->frame.planes[p]) {
2118 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
2119 "from layer %d plane %d of DRM frame: %d.\n",
2125 dst->data[p] = (uint8_t*)mapping->frame.planes[p];
2126 mapping->frame.nb_planes = ++p;
2130 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2131 &opencl_unmap_from_drm_beignet,
2136 dst->width = src->width;
2137 dst->height = src->height;
2142 for (p = 0; p < mapping->frame.nb_planes; p++) {
2143 if (mapping->frame.planes[p])
2144 clReleaseMemObject(mapping->frame.planes[p]);
2150 #if HAVE_OPENCL_VAAPI_BEIGNET
2152 static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc,
2153 AVFrame *dst, const AVFrame *src,
2156 HWMapDescriptor *hwmap;
2160 tmp = av_frame_alloc();
2162 return AVERROR(ENOMEM);
2164 tmp->format = AV_PIX_FMT_DRM_PRIME;
2166 err = av_hwframe_map(tmp, src, flags);
2170 err = opencl_map_from_drm_beignet(dst_fc, dst, tmp, flags);
2174 // Adjust the map descriptor so that unmap works correctly.
2175 hwmap = (HWMapDescriptor*)dst->buf[0]->data;
2176 av_frame_unref(hwmap->source);
2177 err = av_frame_ref(hwmap->source, src);
2180 av_frame_free(&tmp);
2184 #endif /* HAVE_OPENCL_VAAPI_BEIGNET */
2185 #endif /* HAVE_OPENCL_DRM_BEIGNET */
2187 static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags)
2189 if ((map_flags & AV_HWFRAME_MAP_READ) &&
2190 (map_flags & AV_HWFRAME_MAP_WRITE))
2191 return CL_MEM_READ_WRITE;
2192 else if (map_flags & AV_HWFRAME_MAP_READ)
2193 return CL_MEM_READ_ONLY;
2194 else if (map_flags & AV_HWFRAME_MAP_WRITE)
2195 return CL_MEM_WRITE_ONLY;
2200 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2202 static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc,
2203 HWMapDescriptor *hwmap)
2205 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2206 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2207 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2212 av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n");
2214 cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL(
2215 frames_priv->command_queue, desc->nb_planes, desc->planes,
2217 if (cle != CL_SUCCESS) {
2218 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2219 "handles: %d.\n", cle);
2222 opencl_wait_events(dst_fc, &event, 1);
2224 for (p = 0; p < desc->nb_planes; p++) {
2225 cle = clReleaseMemObject(desc->planes[p]);
2226 if (cle != CL_SUCCESS) {
2227 av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL "
2228 "image of plane %d of QSV/VAAPI surface: %d\n",
2236 static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst,
2237 const AVFrame *src, int flags)
2239 AVHWFramesContext *src_fc =
2240 (AVHWFramesContext*)src->hw_frames_ctx->data;
2241 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2242 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2243 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2244 AVOpenCLFrameDescriptor *desc;
2245 VASurfaceID va_surface;
2246 cl_mem_flags cl_flags;
2251 if (src->format == AV_PIX_FMT_QSV) {
2252 mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3];
2253 va_surface = *(VASurfaceID*)mfx_surface->Data.MemId;
2254 } else if (src->format == AV_PIX_FMT_VAAPI) {
2255 va_surface = (VASurfaceID)(uintptr_t)src->data[3];
2257 return AVERROR(ENOSYS);
2260 cl_flags = opencl_mem_flags_for_mapping(flags);
2262 return AVERROR(EINVAL);
2264 av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to "
2265 "OpenCL.\n", va_surface);
2267 desc = av_mallocz(sizeof(*desc));
2269 return AVERROR(ENOMEM);
2271 // The cl_intel_va_api_media_sharing extension only supports NV12
2272 // surfaces, so for now there are always exactly two planes.
2273 desc->nb_planes = 2;
2275 for (p = 0; p < desc->nb_planes; p++) {
2277 device_priv->clCreateFromVA_APIMediaSurfaceINTEL(
2278 dst_dev->context, cl_flags, &va_surface, p, &cle);
2279 if (!desc->planes[p]) {
2280 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2281 "image from plane %d of QSV/VAAPI surface "
2282 "%#x: %d.\n", p, va_surface, cle);
2287 dst->data[p] = (uint8_t*)desc->planes[p];
2290 cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL(
2291 frames_priv->command_queue, desc->nb_planes, desc->planes,
2293 if (cle != CL_SUCCESS) {
2294 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2295 "handles: %d.\n", cle);
2300 err = opencl_wait_events(dst_fc, &event, 1);
2304 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2305 &opencl_unmap_from_qsv, desc);
2309 dst->width = src->width;
2310 dst->height = src->height;
2315 for (p = 0; p < desc->nb_planes; p++)
2316 if (desc->planes[p])
2317 clReleaseMemObject(desc->planes[p]);
2324 #if HAVE_OPENCL_DXVA2
2326 static void opencl_unmap_from_dxva2(AVHWFramesContext *dst_fc,
2327 HWMapDescriptor *hwmap)
2329 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2330 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2331 OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
2335 av_log(dst_fc, AV_LOG_DEBUG, "Unmap DXVA2 surface from OpenCL.\n");
2337 cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
2338 frames_priv->command_queue, desc->nb_planes, desc->planes,
2340 if (cle != CL_SUCCESS) {
2341 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2342 "handle: %d.\n", cle);
2346 opencl_wait_events(dst_fc, &event, 1);
2349 static int opencl_map_from_dxva2(AVHWFramesContext *dst_fc, AVFrame *dst,
2350 const AVFrame *src, int flags)
2352 AVHWFramesContext *src_fc =
2353 (AVHWFramesContext*)src->hw_frames_ctx->data;
2354 AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
2355 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2356 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2357 AVOpenCLFrameDescriptor *desc;
2362 av_log(dst_fc, AV_LOG_DEBUG, "Map DXVA2 surface %p to "
2363 "OpenCL.\n", src->data[3]);
2365 for (i = 0; i < src_hwctx->nb_surfaces; i++) {
2366 if (src_hwctx->surfaces[i] == (IDirect3DSurface9*)src->data[3])
2369 if (i >= src_hwctx->nb_surfaces) {
2370 av_log(dst_fc, AV_LOG_ERROR, "Trying to map from a surface which "
2371 "is not in the mapped frames context.\n");
2372 return AVERROR(EINVAL);
2375 desc = &frames_priv->mapped_frames[i];
2377 cle = device_priv->clEnqueueAcquireDX9MediaSurfacesKHR(
2378 frames_priv->command_queue, desc->nb_planes, desc->planes,
2380 if (cle != CL_SUCCESS) {
2381 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2382 "handle: %d.\n", cle);
2383 return AVERROR(EIO);
2386 err = opencl_wait_events(dst_fc, &event, 1);
2390 for (i = 0; i < desc->nb_planes; i++)
2391 dst->data[i] = (uint8_t*)desc->planes[i];
2393 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2394 &opencl_unmap_from_dxva2, desc);
2398 dst->width = src->width;
2399 dst->height = src->height;
2404 cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR(
2405 frames_priv->command_queue, desc->nb_planes, desc->planes,
2407 if (cle == CL_SUCCESS)
2408 opencl_wait_events(dst_fc, &event, 1);
2412 static int opencl_frames_derive_from_dxva2(AVHWFramesContext *dst_fc,
2413 AVHWFramesContext *src_fc, int flags)
2415 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2416 AVDXVA2FramesContext *src_hwctx = src_fc->hwctx;
2417 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2418 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2419 cl_mem_flags cl_flags;
2421 int err, i, p, nb_planes;
2423 if (src_fc->sw_format != AV_PIX_FMT_NV12) {
2424 av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
2425 "for DXVA2 to OpenCL mapping.\n");
2426 return AVERROR(EINVAL);
2430 if (src_fc->initial_pool_size == 0) {
2431 av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
2432 "for DXVA2 to OpenCL mapping.\n");
2433 return AVERROR(EINVAL);
2436 cl_flags = opencl_mem_flags_for_mapping(flags);
2438 return AVERROR(EINVAL);
2440 frames_priv->nb_mapped_frames = src_hwctx->nb_surfaces;
2442 frames_priv->mapped_frames =
2443 av_mallocz_array(frames_priv->nb_mapped_frames,
2444 sizeof(*frames_priv->mapped_frames));
2445 if (!frames_priv->mapped_frames)
2446 return AVERROR(ENOMEM);
2448 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2449 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2450 cl_dx9_surface_info_khr surface_info = {
2451 .resource = src_hwctx->surfaces[i],
2452 .shared_handle = NULL,
2454 desc->nb_planes = nb_planes;
2455 for (p = 0; p < nb_planes; p++) {
2457 device_priv->clCreateFromDX9MediaSurfaceKHR(
2458 dst_dev->context, cl_flags,
2459 device_priv->dx9_media_adapter_type,
2460 &surface_info, p, &cle);
2461 if (!desc->planes[p]) {
2462 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2463 "image from plane %d of DXVA2 surface %d: %d.\n",
2474 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2475 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2476 for (p = 0; p < desc->nb_planes; p++) {
2477 if (desc->planes[p])
2478 clReleaseMemObject(desc->planes[p]);
2481 av_freep(&frames_priv->mapped_frames);
2482 frames_priv->nb_mapped_frames = 0;
2488 #if HAVE_OPENCL_D3D11
2490 static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc,
2491 HWMapDescriptor *hwmap)
2493 AVOpenCLFrameDescriptor *desc = hwmap->priv;
2494 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2495 OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv;
2499 cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2500 frames_priv->command_queue, desc->nb_planes, desc->planes,
2502 if (cle != CL_SUCCESS) {
2503 av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface "
2504 "handle: %d.\n", cle);
2507 opencl_wait_events(dst_fc, &event, 1);
2510 static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst,
2511 const AVFrame *src, int flags)
2513 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2514 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2515 AVOpenCLFrameDescriptor *desc;
2520 index = (intptr_t)src->data[1];
2521 if (index >= frames_priv->nb_mapped_frames) {
2522 av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for "
2523 "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames);
2524 return AVERROR(EINVAL);
2527 av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n",
2530 desc = &frames_priv->mapped_frames[index];
2532 cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR(
2533 frames_priv->command_queue, desc->nb_planes, desc->planes,
2535 if (cle != CL_SUCCESS) {
2536 av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface "
2537 "handle: %d.\n", cle);
2538 return AVERROR(EIO);
2541 err = opencl_wait_events(dst_fc, &event, 1);
2545 for (i = 0; i < desc->nb_planes; i++)
2546 dst->data[i] = (uint8_t*)desc->planes[i];
2548 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2549 &opencl_unmap_from_d3d11, desc);
2553 dst->width = src->width;
2554 dst->height = src->height;
2559 cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR(
2560 frames_priv->command_queue, desc->nb_planes, desc->planes,
2562 if (cle == CL_SUCCESS)
2563 opencl_wait_events(dst_fc, &event, 1);
2567 static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc,
2568 AVHWFramesContext *src_fc, int flags)
2570 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2571 AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx;
2572 OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv;
2573 OpenCLFramesContext *frames_priv = dst_fc->internal->priv;
2574 cl_mem_flags cl_flags;
2576 int err, i, p, nb_planes;
2578 if (src_fc->sw_format != AV_PIX_FMT_NV12) {
2579 av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported "
2580 "for D3D11 to OpenCL mapping.\n");
2581 return AVERROR(EINVAL);
2585 if (src_fc->initial_pool_size == 0) {
2586 av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported "
2587 "for D3D11 to OpenCL mapping.\n");
2588 return AVERROR(EINVAL);
2591 cl_flags = opencl_mem_flags_for_mapping(flags);
2593 return AVERROR(EINVAL);
2595 frames_priv->nb_mapped_frames = src_fc->initial_pool_size;
2597 frames_priv->mapped_frames =
2598 av_mallocz_array(frames_priv->nb_mapped_frames,
2599 sizeof(*frames_priv->mapped_frames));
2600 if (!frames_priv->mapped_frames)
2601 return AVERROR(ENOMEM);
2603 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2604 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2605 desc->nb_planes = nb_planes;
2606 for (p = 0; p < nb_planes; p++) {
2607 UINT subresource = 2 * i + p;
2610 device_priv->clCreateFromD3D11Texture2DKHR(
2611 dst_dev->context, cl_flags, src_hwctx->texture,
2613 if (!desc->planes[p]) {
2614 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL "
2615 "image from plane %d of D3D texture "
2616 "index %d (subresource %u): %d.\n",
2617 p, i, (unsigned int)subresource, cle);
2627 for (i = 0; i < frames_priv->nb_mapped_frames; i++) {
2628 AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i];
2629 for (p = 0; p < desc->nb_planes; p++) {
2630 if (desc->planes[p])
2631 clReleaseMemObject(desc->planes[p]);
2634 av_freep(&frames_priv->mapped_frames);
2635 frames_priv->nb_mapped_frames = 0;
2641 #if HAVE_OPENCL_DRM_ARM
2643 typedef struct DRMARMtoOpenCLMapping {
2645 cl_mem object_buffers[AV_DRM_MAX_PLANES];
2647 cl_mem plane_images[AV_DRM_MAX_PLANES];
2648 } DRMARMtoOpenCLMapping;
2650 static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc,
2651 HWMapDescriptor *hwmap)
2653 DRMARMtoOpenCLMapping *mapping = hwmap->priv;
2656 for (i = 0; i < mapping->nb_planes; i++)
2657 clReleaseMemObject(mapping->plane_images[i]);
2659 for (i = 0; i < mapping->nb_objects; i++)
2660 clReleaseMemObject(mapping->object_buffers[i]);
2665 static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst,
2666 const AVFrame *src, int flags)
2668 AVHWFramesContext *src_fc =
2669 (AVHWFramesContext*)src->hw_frames_ctx->data;
2670 AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
2671 const AVDRMFrameDescriptor *desc;
2672 DRMARMtoOpenCLMapping *mapping = NULL;
2673 cl_mem_flags cl_flags;
2674 const cl_import_properties_arm props[3] = {
2675 CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0,
2680 desc = (const AVDRMFrameDescriptor*)src->data[0];
2682 cl_flags = opencl_mem_flags_for_mapping(flags);
2684 return AVERROR(EINVAL);
2686 mapping = av_mallocz(sizeof(*mapping));
2688 return AVERROR(ENOMEM);
2690 mapping->nb_objects = desc->nb_objects;
2691 for (i = 0; i < desc->nb_objects; i++) {
2692 int fd = desc->objects[i].fd;
2694 av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd);
2696 if (desc->objects[i].format_modifier) {
2697 av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has "
2698 "nonzero format modifier %"PRId64", result may not "
2699 "be as expected.\n", i, fd,
2700 desc->objects[i].format_modifier);
2703 mapping->object_buffers[i] =
2704 clImportMemoryARM(dst_dev->context, cl_flags, props,
2705 &fd, desc->objects[i].size, &cle);
2706 if (!mapping->object_buffers[i]) {
2707 av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer "
2708 "from object %d (fd %d, size %"SIZE_SPECIFIER") of DRM frame: %d.\n",
2709 i, fd, desc->objects[i].size, cle);
2715 mapping->nb_planes = 0;
2716 for (i = 0; i < desc->nb_layers; i++) {
2717 const AVDRMLayerDescriptor *layer = &desc->layers[i];
2719 for (j = 0; j < layer->nb_planes; j++) {
2720 const AVDRMPlaneDescriptor *plane = &layer->planes[j];
2721 cl_mem plane_buffer;
2722 cl_image_format image_format;
2723 cl_image_desc image_desc;
2724 cl_buffer_region region;
2725 int p = mapping->nb_planes;
2727 err = opencl_get_plane_format(src_fc->sw_format, p,
2728 src_fc->width, src_fc->height,
2729 &image_format, &image_desc);
2731 av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM "
2732 "layer %d plane %d): %d.\n", p, i, j, err);
2736 region.origin = plane->offset;
2737 region.size = image_desc.image_row_pitch *
2738 image_desc.image_height;
2741 clCreateSubBuffer(mapping->object_buffers[plane->object_index],
2743 CL_BUFFER_CREATE_TYPE_REGION,
2745 if (!plane_buffer) {
2746 av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer "
2747 "for plane %d: %d.\n", p, cle);
2752 image_desc.buffer = plane_buffer;
2754 mapping->plane_images[p] =
2755 clCreateImage(dst_dev->context, cl_flags,
2756 &image_format, &image_desc, NULL, &cle);
2758 // Unreference the sub-buffer immediately - we don't need it
2759 // directly and a reference is held by the image.
2760 clReleaseMemObject(plane_buffer);
2762 if (!mapping->plane_images[p]) {
2763 av_log(dst_fc, AV_LOG_ERROR, "Failed to create image "
2764 "for plane %d: %d.\n", p, cle);
2769 ++mapping->nb_planes;
2773 for (i = 0; i < mapping->nb_planes; i++)
2774 dst->data[i] = (uint8_t*)mapping->plane_images[i];
2776 err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
2777 &opencl_unmap_from_drm_arm, mapping);
2781 dst->width = src->width;
2782 dst->height = src->height;
2787 for (i = 0; i < mapping->nb_planes; i++) {
2788 clReleaseMemObject(mapping->plane_images[i]);
2790 for (i = 0; i < mapping->nb_objects; i++) {
2791 if (mapping->object_buffers[i])
2792 clReleaseMemObject(mapping->object_buffers[i]);
2800 static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
2801 const AVFrame *src, int flags)
2803 av_assert0(src->format == AV_PIX_FMT_OPENCL);
2804 if (hwfc->sw_format != dst->format)
2805 return AVERROR(ENOSYS);
2806 return opencl_map_frame(hwfc, dst, src, flags);
2809 static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
2810 const AVFrame *src, int flags)
2812 OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
2813 av_assert0(dst->format == AV_PIX_FMT_OPENCL);
2814 switch (src->format) {
2815 #if HAVE_OPENCL_DRM_BEIGNET
2816 case AV_PIX_FMT_DRM_PRIME:
2817 if (priv->beignet_drm_mapping_usable)
2818 return opencl_map_from_drm_beignet(hwfc, dst, src, flags);
2820 #if HAVE_OPENCL_VAAPI_BEIGNET
2821 case AV_PIX_FMT_VAAPI:
2822 if (priv->beignet_drm_mapping_usable)
2823 return opencl_map_from_vaapi(hwfc, dst, src, flags);
2825 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2826 case AV_PIX_FMT_QSV:
2827 case AV_PIX_FMT_VAAPI:
2828 if (priv->qsv_mapping_usable)
2829 return opencl_map_from_qsv(hwfc, dst, src, flags);
2831 #if HAVE_OPENCL_DXVA2
2832 case AV_PIX_FMT_DXVA2_VLD:
2833 if (priv->dxva2_mapping_usable)
2834 return opencl_map_from_dxva2(hwfc, dst, src, flags);
2836 #if HAVE_OPENCL_D3D11
2837 case AV_PIX_FMT_D3D11:
2838 if (priv->d3d11_mapping_usable)
2839 return opencl_map_from_d3d11(hwfc, dst, src, flags);
2841 #if HAVE_OPENCL_DRM_ARM
2842 case AV_PIX_FMT_DRM_PRIME:
2843 if (priv->drm_arm_mapping_usable)
2844 return opencl_map_from_drm_arm(hwfc, dst, src, flags);
2847 return AVERROR(ENOSYS);
2850 static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
2851 AVHWFramesContext *src_fc, int flags)
2853 OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
2854 switch (src_fc->device_ctx->type) {
2855 #if HAVE_OPENCL_DRM_BEIGNET
2856 case AV_HWDEVICE_TYPE_DRM:
2857 if (!priv->beignet_drm_mapping_usable)
2858 return AVERROR(ENOSYS);
2861 #if HAVE_OPENCL_VAAPI_BEIGNET
2862 case AV_HWDEVICE_TYPE_VAAPI:
2863 if (!priv->beignet_drm_mapping_usable)
2864 return AVERROR(ENOSYS);
2867 #if HAVE_OPENCL_VAAPI_INTEL_MEDIA
2868 case AV_HWDEVICE_TYPE_QSV:
2869 case AV_HWDEVICE_TYPE_VAAPI:
2870 if (!priv->qsv_mapping_usable)
2871 return AVERROR(ENOSYS);
2874 #if HAVE_OPENCL_DXVA2
2875 case AV_HWDEVICE_TYPE_DXVA2:
2876 if (!priv->dxva2_mapping_usable)
2877 return AVERROR(ENOSYS);
2880 err = opencl_frames_derive_from_dxva2(dst_fc, src_fc, flags);
2886 #if HAVE_OPENCL_D3D11
2887 case AV_HWDEVICE_TYPE_D3D11VA:
2888 if (!priv->d3d11_mapping_usable)
2889 return AVERROR(ENOSYS);
2892 err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags);
2898 #if HAVE_OPENCL_DRM_ARM
2899 case AV_HWDEVICE_TYPE_DRM:
2900 if (!priv->drm_arm_mapping_usable)
2901 return AVERROR(ENOSYS);
2905 return AVERROR(ENOSYS);
2907 return opencl_frames_init_command_queue(dst_fc);
2910 const HWContextType ff_hwcontext_type_opencl = {
2911 .type = AV_HWDEVICE_TYPE_OPENCL,
2914 .device_hwctx_size = sizeof(AVOpenCLDeviceContext),
2915 .device_priv_size = sizeof(OpenCLDeviceContext),
2916 .frames_hwctx_size = sizeof(AVOpenCLFramesContext),
2917 .frames_priv_size = sizeof(OpenCLFramesContext),
2919 .device_create = &opencl_device_create,
2920 .device_derive = &opencl_device_derive,
2921 .device_init = &opencl_device_init,
2922 .device_uninit = &opencl_device_uninit,
2924 .frames_get_constraints = &opencl_frames_get_constraints,
2925 .frames_init = &opencl_frames_init,
2926 .frames_uninit = &opencl_frames_uninit,
2927 .frames_get_buffer = &opencl_get_buffer,
2929 .transfer_get_formats = &opencl_transfer_get_formats,
2930 .transfer_data_to = &opencl_transfer_data_to,
2931 .transfer_data_from = &opencl_transfer_data_from,
2933 .map_from = &opencl_map_from,
2934 .map_to = &opencl_map_to,
2935 .frames_derive_to = &opencl_frames_derive_to,
2937 .pix_fmts = (const enum AVPixelFormat[]) {