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