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