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

Lionel Landwerlin lionel.g.landwerlin at intel.com
Sun May 10 23:01:07 CEST 2020


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)
+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



More information about the vlc-devel mailing list