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