[vlc-devel] [PATCH v2 2/2] vaapi: add support for DRM modifiers

Thomas Guillem thomas at gllm.fr
Mon May 11 13:05:22 CEST 2020


Hello,

On Sun, May 10, 2020, at 23:01, Lionel Landwerlin wrote:
> DRM modifiers communicate a description of the data layout in the
> buffers exported/imported through various API.
> 
> On Intel HW this exports tiling information as well as potential
> compression.
> 
> v2: Make modifier usage conditional to the appropriate vaapi version
> 
> v3: Don't touch configure.ac
>     Use VA_CHECK_VERSION()
> ---
>  modules/hw/vaapi/vlc_vaapi.c                | 15 ++++
>  modules/hw/vaapi/vlc_vaapi.h                | 10 +++
>  modules/video_output/opengl/interop_vaapi.c | 91 +++++++++++++++++++--
>  3 files changed, 108 insertions(+), 8 deletions(-)
> 
> diff --git a/modules/hw/vaapi/vlc_vaapi.c b/modules/hw/vaapi/vlc_vaapi.c
> index 8a4dc6023d..31304fd6c3 100644
> --- a/modules/hw/vaapi/vlc_vaapi.c
> +++ b/modules/hw/vaapi/vlc_vaapi.c
> @@ -589,3 +589,18 @@ vlc_vaapi_PicGetDisplay(picture_t *pic)
>      struct vaapi_pic_context *pic_ctx = (struct vaapi_pic_context 
> *)pic->context;
>      return pic_ctx->va_dpy;
>  }
> +
> +#if VA_CHECK_VERSION(1, 1, 0)
> +int
> +vlc_vaapi_ExportSurfaceHandle(vlc_object_t *o,
> +                              VADisplay dpy,
> +                              VASurfaceID surface,
> +                              uint32_t mem_type,
> +                              uint32_t flags,
> +                              void *descriptor)
> +{
> +    VA_CALL(o, vaExportSurfaceHandle, dpy, surface, mem_type, flags, 
> descriptor);
> +    return VLC_SUCCESS;
> +error: return VLC_EGENERIC;
> +}
> +#endif
> diff --git a/modules/hw/vaapi/vlc_vaapi.h b/modules/hw/vaapi/vlc_vaapi.h
> index ffcf68205f..95de6f07c7 100644
> --- a/modules/hw/vaapi/vlc_vaapi.h
> +++ b/modules/hw/vaapi/vlc_vaapi.h
> @@ -199,6 +199,16 @@ vlc_vaapi_IsChromaOpaque(int i_vlc_chroma)
>  
>  void vlc_chroma_to_vaapi(int i_vlc_chroma, unsigned *va_rt_format, int 
> *va_fourcc);
>  
> +#ifdef VA_CHECK_VERSION(1, 1, 0)

Typo here, It should be #if VA_CHECK_VERSION(1, 1, 0)

> +int
> +vlc_vaapi_ExportSurfaceHandle(vlc_object_t *o,
> +                              VADisplay dpy,
> +                              VASurfaceID surface,
> +                              uint32_t mem_type,
> +                              uint32_t flags,
> +                              void *descriptor);
> +#endif
> +
>  /* This macro is designed to wrap any VA call, and in case of failure,
>     display the VA error string then goto the 'error' label (which you 
> must
>     define). */
> diff --git a/modules/video_output/opengl/interop_vaapi.c 
> b/modules/video_output/opengl/interop_vaapi.c
> index 27d9e0ec2d..1f79ccc431 100644
> --- a/modules/video_output/opengl/interop_vaapi.c
> +++ b/modules/video_output/opengl/interop_vaapi.c
> @@ -46,6 +46,15 @@ typedef void *GLeglImageOES;
>  typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target, 
> GLeglImageOES image);
>  #endif
>  
> +#define DRM_FORMAT_MOD_VENDOR_NONE    0
> +#define DRM_FORMAT_RESERVED           ((1ULL << 56) - 1)
> +
> +#define fourcc_mod_code(vendor, val) \
> +        ((((EGLuint64KHR)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | 
> ((val) & 0x00ffffffffffffffULL))
> +
> +#define DRM_FORMAT_MOD_INVALID  fourcc_mod_code(NONE, 
> DRM_FORMAT_RESERVED)
> +
> +
>  struct priv
>  {
>      VADisplay vadpy;
> @@ -56,16 +65,23 @@ struct priv
>      EGLint drm_fourccs[3];
>  
>      struct {
> -        picture_t *  pic;
> -        VAImage      va_image;
> -        VABufferInfo va_buffer_info;
> -        void *       egl_images[3];
> +        picture_t *                 pic;
> +#if VA_CHECK_VERSION(1, 1, 0)
> +        /* VADRMPRIMESurfaceDescriptor carries modifier information
> +         * (GPU tiling, compression, etc...) */
> +        VADRMPRIMESurfaceDescriptor va_surface_descriptor;
> +#else
> +        VABufferInfo                va_buffer_info;
> +#endif
> +        VAImage                     va_image;
> +        void *                      egl_images[3];
>      } last;
>  };
>  
>  static EGLImageKHR
>  vaegl_image_create(const struct vlc_gl_interop *interop, EGLint w, 
> EGLint h,
> -                   EGLint fourcc, EGLint fd, EGLint offset, EGLint 
> pitch)
> +                   EGLint fourcc, EGLint fd, EGLint offset, EGLint 
> pitch,
> +                   EGLuint64KHR modifier)
>  {
>      EGLint attribs[] = {
>          EGL_WIDTH, w,
> @@ -74,6 +90,8 @@ vaegl_image_create(const struct vlc_gl_interop 
> *interop, EGLint w, EGLint h,
>          EGL_DMA_BUF_PLANE0_FD_EXT, fd,
>          EGL_DMA_BUF_PLANE0_OFFSET_EXT, offset,
>          EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch,
> +        EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, modifier & 0xffffffff,
> +        EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, modifier >> 32,
>          EGL_NONE
>      };
>  
> @@ -95,7 +113,12 @@ vaegl_release_last_pic(const struct vlc_gl_interop 
> *interop, struct priv *priv)
>      for (unsigned i = 0; i < priv->last.va_image.num_planes; ++i)
>          vaegl_image_destroy(interop, priv->last.egl_images[i]);
>  
> +#if VA_CHECK_VERSION(1, 1, 0)
> +    for (unsigned i = 0; i < priv->last.va_surface_descriptor.num_objects; ++i)
> +        close(priv->last.va_surface_descriptor.objects[i].fd);
> +#else
>      vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, priv->last.va_image.buf);
> +#endif
>  
>      vlc_vaapi_DestroyImage(o, priv->vadpy, priv->last.va_image.image_id);
>  
> @@ -157,14 +180,18 @@ tc_vaegl_update(const struct vlc_gl_interop 
> *interop, GLuint *textures,
>      struct priv *priv = interop->priv;
>      vlc_object_t *o = VLC_OBJECT(interop->gl);
>      VAImage va_image;
> +#if VA_CHECK_VERSION(1, 1, 0)
> +    VADRMPRIMESurfaceDescriptor va_surface_descriptor;
> +#else
>      VABufferInfo va_buffer_info;
> +#endif
>      EGLImageKHR egl_images[3] = { };
>      bool release_image = false, release_buffer_info = false;
>  
>      if (pic == priv->last.pic)
>      {
>          va_image = priv->last.va_image;
> -        va_buffer_info = priv->last.va_buffer_info;
> +        va_surface_descriptor = priv->last.va_surface_descriptor;
>          for (unsigned i = 0; i < priv->last.va_image.num_planes; ++i)
>              egl_images[i] = priv->last.egl_images[i];
>      }
> @@ -177,21 +204,55 @@ tc_vaegl_update(const struct vlc_gl_interop 
> *interop, GLuint *textures,
>  
>          assert(va_image.format.fourcc == priv->fourcc);
>  
> +#if VA_CHECK_VERSION(1, 1, 0)
> +        if (vlc_vaapi_ExportSurfaceHandle(o, priv->vadpy, 
> vlc_vaapi_PicGetSurface(pic),
> +                                          
> VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 0,
> +                                          &va_surface_descriptor))
> +            goto error;
> +#else
>          va_buffer_info = (VABufferInfo) {
>              .mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
>          };
>          if (vlc_vaapi_AcquireBufferHandle(o, priv->vadpy, va_image.buf,
>                                            &va_buffer_info))
>              goto error;
> +#endif
>          release_buffer_info = true;
>      }
>  
> +#if VA_CHECK_VERSION(1, 1, 0)
> +    for (unsigned i = 0; i < va_surface_descriptor.num_layers; ++i)
> +    {
> +        unsigned obj_idx = 
> va_surface_descriptor.layers[i].object_index[0];
> +
> +        /* Since we don't ask for composite object through
> +         * vaExportSurfaceHandle, we shouldn't get any multiplane
> +         * layer. */
> +        if (va_surface_descriptor.layers[i].num_planes > 1)
> +          goto error;
> +
> +        egl_images[i] =
> +            vaegl_image_create(interop, tex_width[i], tex_height[i],
> +                               priv->drm_fourccs[i],
> +                               
> va_surface_descriptor.objects[obj_idx].fd,
> +                               
> va_surface_descriptor.layers[i].offset[0],
> +                               
> va_surface_descriptor.layers[i].pitch[0],
> +                               
> va_surface_descriptor.objects[obj_idx].drm_format_modifier);
> +        if (egl_images[i] == NULL)
> +            goto error;
> +
> +        interop->vt->BindTexture(interop->tex_target, textures[i]);
> +
> +        priv->glEGLImageTargetTexture2DOES(interop->tex_target, 
> egl_images[i]);
> +    }
> +#else
>      for (unsigned i = 0; i < va_image.num_planes; ++i)
>      {
>          egl_images[i] =
>              vaegl_image_create(interop, tex_width[i], tex_height[i],
>                                 priv->drm_fourccs[i], 
> va_buffer_info.handle,
> -                               va_image.offsets[i], 
> va_image.pitches[i]);
> +                               va_image.offsets[i], 
> va_image.pitches[i],
> +                               DRM_FORMAT_MOD_INVALID);
>          if (egl_images[i] == NULL)
>              goto error;
>  
> @@ -199,6 +260,7 @@ tc_vaegl_update(const struct vlc_gl_interop 
> *interop, GLuint *textures,
>  
>          priv->glEGLImageTargetTexture2DOES(interop->tex_target, egl_images[i]);
>      }
> +#endif
>  
>      if (pic != priv->last.pic)
>      {
> @@ -206,7 +268,12 @@ tc_vaegl_update(const struct vlc_gl_interop 
> *interop, GLuint *textures,
>              vaegl_release_last_pic(interop, priv);
>          priv->last.pic = picture_Hold(pic);
>          priv->last.va_image = va_image;
> +#if VA_CHECK_VERSION(1, 1, 0)
> +        priv->last.va_surface_descriptor = va_surface_descriptor;
> +#else
>          priv->last.va_buffer_info = va_buffer_info;
> +#endif
> +
>          for (unsigned i = 0; i < va_image.num_planes; ++i)
>              priv->last.egl_images[i] = egl_images[i];
>      }
> @@ -217,7 +284,14 @@ error:
>      if (release_image)
>      {
>          if (release_buffer_info)
> +        {
> +#if VA_CHECK_VERSION(1, 1, 0)
> +            for (unsigned i = 0; i < 
> va_surface_descriptor.num_objects; ++i)
> +                close(va_surface_descriptor.objects[i].fd);
> +#else
>              vlc_vaapi_ReleaseBufferHandle(o, priv->vadpy, 
> va_image.buf);
> +#endif
> +        }
>  
>          for (unsigned i = 0; i < 3 && egl_images[i] != NULL; ++i)
>              vaegl_image_destroy(interop, egl_images[i]);
> @@ -313,7 +387,8 @@ tc_va_check_derive_image(const struct 
> vlc_gl_interop *interop)
>          EGLint h = (va_image.height * image_desc->p[i].h.num) / 
> image_desc->p[i].h.den;
>          EGLImageKHR egl_image =
>              vaegl_image_create(interop, w, h, priv->drm_fourccs[i], 
> va_buffer_info.handle,
> -                               va_image.offsets[i], 
> va_image.pitches[i]);
> +                               va_image.offsets[i], 
> va_image.pitches[i],
> +                               DRM_FORMAT_MOD_INVALID);
>          if (egl_image == NULL)
>          {
>              msg_Warn(o, "Can't create Image KHR: kernel too old ?");
> -- 
> 2.26.2

Thanks for your work, I tested it on my side. Ready to merge it tomorrow.

(you don't have to resend a patch for the typo, I fixed it on my side).

> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list