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