[FFmpeg-devel] [PATCH 03/15] hwcontext_opencl: VAAPI to OpenCL mapping for Intel i965+beignet

Jun Zhao mypopydev at gmail.com
Wed Nov 22 06:52:05 EET 2017



On 2017/11/15 3:47, Mark Thompson wrote:
> Supports all surface formats in common between the two.
> ---
>  configure                    |   6 +
>  libavutil/hwcontext_opencl.c | 298 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 304 insertions(+)
>
> diff --git a/configure b/configure
> index 167db274f1..dcdb5fee1f 100755
> --- a/configure
> +++ b/configure
> @@ -2121,6 +2121,7 @@ HAVE_LIST="
>      $TYPES_LIST
>      makeinfo
>      makeinfo_html
> +    opencl_vaapi_beignet
>      perl
>      pod2man
>      texi2html
> @@ -6150,6 +6151,11 @@ enabled vaapi &&
>      check_cpp_condition "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" &&
>      enable vaapi_1
>  
> +if enabled_all opencl vaapi ; then
> +    check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" &&
> +        enable opencl_vaapi_beignet
> +fi
> +
>  enabled vdpau &&
>      check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
>      disable vdpau
> diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c
> index 0fe25d9500..7f99f5af3f 100644
> --- a/libavutil/hwcontext_opencl.c
> +++ b/libavutil/hwcontext_opencl.c
> @@ -29,6 +29,14 @@
>  #include "mem.h"
>  #include "pixdesc.h"
>  
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +#include <unistd.h>
> +#include <va/va.h>
> +#include <va/va_drmcommon.h>
> +#include <CL/cl_intel.h>
> +#include "hwcontext_vaapi.h"
> +#endif
> +
>  
>  typedef struct OpenCLDeviceContext {
>      // Default command queue to use for transfer/mapping operations on
> @@ -41,6 +49,10 @@ typedef struct OpenCLDeviceContext {
>      cl_platform_id platform_id;
>  
>      // Platform/device-specific functions.
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +    int vaapi_mapping_usable;
> +    clCreateImageFromFdINTEL_fn  clCreateImageFromFdINTEL;
> +#endif
>  } OpenCLDeviceContext;
>  
>  typedef struct OpenCLFramesContext {
> @@ -589,6 +601,40 @@ static int opencl_device_init(AVHWDeviceContext *hwdev)
>          return AVERROR(EIO);
>      }
>  
> +#define CL_FUNC(name, desc) do {                                \
> +        if (fail)                                               \
> +            break;                                              \
> +        priv->name = clGetExtensionFunctionAddressForPlatform(  \
> +            priv->platform_id, #name);                          \
> +        if (!priv->name) {                                      \
> +            av_log(hwdev, AV_LOG_VERBOSE,                       \
> +                   desc " function not found (%s).\n", #name);  \
> +            fail = 1;                                           \
> +        } else {                                                \
> +            av_log(hwdev, AV_LOG_VERBOSE,                       \
> +                   desc " function found (%s).\n", #name);      \
> +        }                                                       \
> +    } while (0)
> +
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +    {
> +        int fail = 0;
> +
> +        CL_FUNC(clCreateImageFromFdINTEL,
> +                "Intel DRM to OpenCL image mapping");
> +
> +        if (fail) {
> +            av_log(hwdev, AV_LOG_WARNING, "VAAPI to OpenCL mapping "
> +                   "not usable.\n");
> +            priv->vaapi_mapping_usable = 0;
> +        } else {
> +            priv->vaapi_mapping_usable = 1;
> +        }
> +    }
> +#endif
> +
> +#undef CL_FUNC
> +
>      return 0;
>  }
>  
> @@ -606,6 +652,52 @@ static void opencl_device_uninit(AVHWDeviceContext *hwdev)
>      }
>  }
>  
> +static int opencl_device_derive(AVHWDeviceContext *hwdev,
> +                                AVHWDeviceContext *src_ctx,
> +                                int flags)
> +{
> +    int err;
> +    switch (src_ctx->type) {
> +
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +    case AV_HWDEVICE_TYPE_VAAPI:
> +        {
> +            // Surface mapping works via DRM PRIME fds with no special
> +            // initialisation required in advance.  This just finds the
> +            // Beignet ICD by name.
> +            AVDictionary *opts = NULL;
> +
> +            err = av_dict_set(&opts, "platform_vendor", "Intel", 0);
> +            if (err >= 0)
> +                err = av_dict_set(&opts, "platform_version", "beignet", 0);
> +            if (err >= 0) {
> +                OpenCLDeviceSelector selector = {
> +                    .platform_index      = -1,
> +                    .device_index        = 0,
> +                    .context             = opts,
> +                    .enumerate_platforms = &opencl_enumerate_platforms,
> +                    .filter_platform     = &opencl_filter_platform,
> +                    .enumerate_devices   = &opencl_enumerate_devices,
> +                    .filter_device       = NULL,
> +                };
> +                err = opencl_device_create_internal(hwdev, &selector, NULL);
> +            }
> +            av_dict_free(&opts);
> +        }
> +        break;
> +#endif
> +
> +    default:
> +        err = AVERROR(ENOSYS);
> +        break;
> +    }
> +
> +    if (err < 0)
> +        return err;
> +
> +    return opencl_device_init(hwdev);
> +}
> +
>  static int opencl_get_plane_format(enum AVPixelFormat pixfmt,
>                                     int plane, int width, int height,
>                                     cl_image_format *image_format,
> @@ -1263,6 +1355,177 @@ fail:
>      return err;
>  }
>  
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +
> +typedef struct VAAPItoOpenCLMapping {
> +    VAImage      va_image;
> +    VABufferInfo va_buffer_info;
> +
> +    AVOpenCLFrameDescriptor frame;
> +} VAAPItoOpenCLMapping;
> +
> +static void opencl_unmap_from_vaapi(AVHWFramesContext *src_fc,
> +                                    HWMapDescriptor *hwmap)
> +{
> +    VAAPItoOpenCLMapping *mapping = hwmap->priv;
> +    AVVAAPIDeviceContext *src_dev = src_fc->device_ctx->hwctx;
> +    VASurfaceID surface_id;
> +    VAStatus vas;
> +    cl_int cle;
> +    int i;
> +
> +    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
> +    av_log(src_fc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from OpenCL.\n",
> +           surface_id);
> +
> +    for (i = 0; i < mapping->frame.nb_planes; i++) {
> +        cle = clReleaseMemObject(mapping->frame.planes[i]);
> +        if (cle != CL_SUCCESS) {
> +            av_log(src_fc, AV_LOG_ERROR, "Failed to release CL "
> +                   "buffer of plane %d of VA image %#x (derived "
> +                   "from surface %#x): %d.\n", i,
> +                   mapping->va_image.buf, surface_id, cle);
> +        }
> +    }
> +
> +    vas = vaReleaseBufferHandle(src_dev->display,
> +                                mapping->va_image.buf);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(src_fc, AV_LOG_ERROR, "Failed to release buffer "
> +               "handle of image %#x (derived from surface %#x): "
> +               "%d (%s).\n", mapping->va_image.buf, surface_id,
> +               vas, vaErrorStr(vas));
> +    }
> +
> +    vas = vaDestroyImage(src_dev->display,
> +                         mapping->va_image.image_id);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(src_fc, AV_LOG_ERROR, "Failed to destroy image "
> +               "derived from surface %#x: %d (%s).\n",
> +               surface_id, vas, vaErrorStr(vas));
> +    }
> +
> +    av_free(mapping);
> +}
> +
> +static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst,
> +                                 const AVFrame *src, int flags)
> +{
> +    AVHWFramesContext      *src_fc =
> +        (AVHWFramesContext*)src->hw_frames_ctx->data;
> +    AVVAAPIDeviceContext  *src_dev = src_fc->device_ctx->hwctx;
> +    AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
> +    OpenCLDeviceContext      *priv = dst_fc->device_ctx->internal->priv;
> +    VAAPItoOpenCLMapping  *mapping = NULL;
> +    VASurfaceID surface_id;
> +    VAStatus vas;
> +    cl_int cle;
> +    int err, p;
> +
> +    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
> +    av_log(src_fc, AV_LOG_DEBUG, "Map VAAPI surface %#x to OpenCL.\n",
> +           surface_id);
> +
> +    mapping = av_mallocz(sizeof(*mapping));
> +    if (!mapping)
> +        return AVERROR(ENOMEM);
> +
> +    vas = vaDeriveImage(src_dev->display, surface_id,
> +                        &mapping->va_image);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(src_fc, AV_LOG_ERROR, "Failed to derive image from "
> +               "surface %#x: %d (%s).\n",
> +               surface_id, vas, vaErrorStr(vas));
> +        err = AVERROR(EIO);
> +        goto fail;
> +    }
> +
> +    mapping->va_buffer_info.mem_type =
> +        VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
> +
> +    vas = vaAcquireBufferHandle(src_dev->display,
> +                                mapping->va_image.buf,
> +                                &mapping->va_buffer_info);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(src_fc, AV_LOG_ERROR, "Failed to get buffer "
> +               "handle from image %#x (derived from surface %#x): "
> +               "%d (%s).\n", mapping->va_image.buf, surface_id,
> +               vas, vaErrorStr(vas));
> +        vaDestroyImage(src_dev->display, mapping->va_image.buf);
> +        err = AVERROR(EIO);
> +        goto fail_derived;
> +    }
> +
> +    av_log(dst_fc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
> +           mapping->va_buffer_info.handle);
> +
> +    mapping->frame.nb_planes = mapping->va_image.num_planes;
> +    for (p = 0; p < mapping->frame.nb_planes; p++) {
> +        cl_import_image_info_intel image_info = {
> +            .fd   = mapping->va_buffer_info.handle,
> +            .size = mapping->va_buffer_info.mem_size,
> +            .type = CL_MEM_OBJECT_IMAGE2D,
> +            .offset    = mapping->va_image.offsets[p],
> +            .row_pitch = mapping->va_image.pitches[p],
> +        };
> +        cl_image_desc image_desc;
> +
> +        err = opencl_get_plane_format(src_fc->sw_format, p,
> +                                      mapping->va_image.width,
> +                                      mapping->va_image.height,
> +                                      &image_info.fmt,
> +                                      &image_desc);
> +        if (err < 0) {
> +            av_log(dst_fc, AV_LOG_ERROR, "VA %#x (derived from "
> +                   "surface %#x) has invalid parameters: %d.\n",
> +                   mapping->va_image.buf, surface_id, err);
> +            goto fail_mapped;
> +        }
> +        image_info.width  = image_desc.image_width;
> +        image_info.height = image_desc.image_height;
> +
> +        mapping->frame.planes[p] =
> +            priv->clCreateImageFromFdINTEL(dst_dev->context,
> +                                           &image_info, &cle);
> +        if (!mapping->frame.planes[p]) {
> +            av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image "
> +                   "from plane %d of VA image %#x (derived from "
> +                   "surface %#x): %d.\n", p,
> +                   mapping->va_image.buf, surface_id, cle);
> +            err = AVERROR(EIO);
> +            goto fail_mapped;
> +        }
> +
> +        dst->data[p] = (uint8_t*)mapping->frame.planes[p];
> +    }
> +
> +    err = ff_hwframe_map_create(src->hw_frames_ctx,
> +                                dst, src, &opencl_unmap_from_vaapi,
> +                                mapping);
> +    if (err < 0)
> +        goto fail_mapped;
> +
> +    dst->width  = src->width;
> +    dst->height = src->height;
> +
> +    return 0;
> +
> +fail_mapped:
> +    for (p = 0; p < mapping->frame.nb_planes; p++) {
> +        if (mapping->frame.planes[p])
> +            clReleaseMemObject(mapping->frame.planes[p]);
> +    }
> +    vaReleaseBufferHandle(src_dev->display, mapping->va_image.buf);
> +fail_derived:
> +    vaDestroyImage(src_dev->display, mapping->va_image.image_id);
> +fail:
> +    av_freep(&mapping);
> +    return err;
> +}
> +
> +#endif
> +
> +
>  static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
>                             const AVFrame *src, int flags)
>  {
> @@ -1272,6 +1535,38 @@ static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
>      return opencl_map_frame(hwfc, dst, src, flags);
>  }
>  
> +static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
> +                         const AVFrame *src, int flags)
> +{
> +    OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv;
> +    av_assert0(dst->format == AV_PIX_FMT_OPENCL);
> +    switch (src->format) {
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +    case AV_PIX_FMT_VAAPI:
> +        if (priv->vaapi_mapping_usable)
> +            return opencl_map_from_vaapi(hwfc, dst, src, flags);
> +#endif
> +    }
> +    return AVERROR(ENOSYS);
> +}
> +
> +static int opencl_frames_derive_to(AVHWFramesContext *dst_fc,
> +                                   AVHWFramesContext *src_fc, int flags)
> +{
> +    OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv;
> +    switch (src_fc->device_ctx->type) {
> +#if HAVE_OPENCL_VAAPI_BEIGNET
> +    case AV_HWDEVICE_TYPE_VAAPI:
> +        if (!priv->vaapi_mapping_usable)
> +            return AVERROR(ENOSYS);
> +        break;
> +#endif
> +    default:
> +        return AVERROR(ENOSYS);
> +    }
> +    return opencl_frames_init_command_queue(dst_fc);
> +}
> +
>  const HWContextType ff_hwcontext_type_opencl = {
>      .type                   = AV_HWDEVICE_TYPE_OPENCL,
>      .name                   = "OpenCL",
> @@ -1282,6 +1577,7 @@ const HWContextType ff_hwcontext_type_opencl = {
>      .frames_priv_size       = sizeof(OpenCLFramesContext),
>  
>      .device_create          = &opencl_device_create,
> +    .device_derive          = &opencl_device_derive,
>      .device_init            = &opencl_device_init,
>      .device_uninit          = &opencl_device_uninit,
>  
> @@ -1295,6 +1591,8 @@ const HWContextType ff_hwcontext_type_opencl = {
>      .transfer_data_from     = &opencl_transfer_data_from,
>  
>      .map_from               = &opencl_map_from,
> +    .map_to                 = &opencl_map_to,
> +    .frames_derive_to       = &opencl_frames_derive_to,
>  
>      .pix_fmts = (const enum AVPixelFormat[]) {
>          AV_PIX_FMT_OPENCL,
LGTM, reviewed and tested.


More information about the ffmpeg-devel mailing list