[vlc-devel] [PATCH 2/2] vaapi: add support for DRM modifiers
Lionel Landwerlin
lionel.g.landwerlin at intel.com
Sun May 10 16:56:36 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
---
configure.ac | 9 ++
modules/hw/vaapi/vlc_vaapi.c | 15 ++++
modules/hw/vaapi/vlc_vaapi.h | 10 +++
modules/video_output/opengl/interop_vaapi.c | 91 +++++++++++++++++++--
4 files changed, 117 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index cc682e94c3..6372eb1514 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2608,6 +2608,7 @@ AS_IF([test "${enable_libva}" = "yes" -a "${have_avcodec}" != "yes" ], [
])
have_vaapi="no"
+have_vaapi_11="no"
have_vaapi_drm="no"
have_vaapi_x11="no"
have_vaapi_wl="no"
@@ -2621,6 +2622,13 @@ AS_IF([test "${enable_libva}" != "no"], [
AC_MSG_WARN([${LIBVA_PKG_ERRORS}.])
])
])
+ PKG_CHECK_MODULES([LIBVA_11], [libva >= 1.1], [
+ have_vaapi_11="yes"
+ ], [
+ AS_IF([test "${enable_libva}"], [
+ AC_MSG_WARN([${LIBVA_PKG_ERRORS}.])
+ ])
+ ])
PKG_CHECK_MODULES([LIBVA_DRM], [libva-drm], [
have_vaapi_drm="yes"
], [
@@ -2641,6 +2649,7 @@ AM_CONDITIONAL([HAVE_VAAPI], [test "${have_vaapi}" = "yes"])
AM_CONDITIONAL([HAVE_VAAPI_DRM], [test "${have_vaapi_drm}" = "yes"])
AM_CONDITIONAL([HAVE_VAAPI_X11], [test "${have_vaapi_x11}" = "yes"])
AM_CONDITIONAL([HAVE_VAAPI_WL], [test "${have_vaapi_wl}" = "yes"])
+AC_DEFINE([HAVE_VAAPI_11], [test "${have_vaapi_11}" = "yes"], [Define if VAAPI 1.1 is available])
have_avcodec_vaapi="no"
AS_IF([test "${have_vaapi}" = "yes" -a "${have_avcodec}" = "yes"], [
diff --git a/modules/hw/vaapi/vlc_vaapi.c b/modules/hw/vaapi/vlc_vaapi.c
index 8a4dc6023d..cf0c2f0fc8 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;
}
+
+#ifdef HAVE_VAAPI_11
+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..e8a2d946dd 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 HAVE_VAAPI_11
+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..1cb60035cd 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;
+#ifdef HAVE_VAAPI_11
+ /* 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]);
+#ifdef HAVE_VAAPI_11
+ 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;
+#ifdef HAVE_VAAPI_11
+ 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);
+#ifdef HAVE_VAAPI_11
+ 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;
}
+#ifdef HAVE_VAAPI_11
+ 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;
+#ifdef HAVE_VAAPI_11
+ 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)
+ {
+#ifdef HAVE_VAAPI_11
+ 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