[vlc-commits] [Git][videolan/vlc][master] 9 commits: drm: return number of formats

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Thu Mar 24 10:02:30 UTC 2022



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
78af9d20 by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: return number of formats

After selecting a plane, we presumably will need to query its formats.
Since we already know how many there are.

- - - - -
854bbb4a by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: add helper to negotiate a pixel format

- - - - -
2f34395f by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm/fourcc: fix copy-paste errors

- - - - -
e8b50862 by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm/fourcc: add helper to convert DRM to VLC format

This extra function is needed to deal with the RGB masks.

- - - - -
e3e92d8c by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: select pixel format as other displays do

Use the helpers from the previous changesets and the follow the common
chroma fallback lists.

This should fix mismatched colour (masks) with RGB formats. This also
enables the use of a bunch of formats not included in the static table
from display.c.

- - - - -
570bed45 by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: remove no longer format negotiation code

This removes the notoriously nonreentrant global format table.
This also incidentally removes the dependency on `-ldrm`.

- - - - -
743fa40a by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: remove unnecessary private data fields

- - - - -
dc8f95ec by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: initialise sys explicitly

- - - - -
eca00803 by Rémi Denis-Courmont at 2022-03-24T09:31:37+00:00
drm: fix potential out of bound read

If the specified chroma had only 1 or 2 characters, this would overflow.

- - - - -


5 changed files:

- modules/video_output/Makefile.am
- modules/video_output/drm/display.c
- modules/video_output/drm/fourcc.c
- modules/video_output/drm/planes.c
- modules/video_output/drm/vlc_drm.h


Changes:

=====================================
modules/video_output/Makefile.am
=====================================
@@ -327,7 +327,6 @@ libdrm_display_plugin_la_SOURCES = \
 	video_output/drm/planes.c \
 	video_output/drm/display.c
 libdrm_display_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(KMS_CFLAGS)
-libdrm_display_plugin_la_LIBADD = $(KMS_LIBS)
 if HAVE_KMS
 vout_LTLIBRARIES += libkms_plugin.la libdrm_display_plugin.la
 endif


=====================================
modules/video_output/drm/display.c
=====================================
@@ -33,10 +33,7 @@
 # include "config.h"
 #endif
 
-#include <xf86drm.h>
-#include <xf86drmMode.h>
 #include <drm_mode.h>
-#include <drm_fourcc.h>
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
@@ -64,147 +61,12 @@ typedef struct vout_display_sys_t {
     picture_t       *buffers[MAXHWBUF];
 
     unsigned int    front_buf;
-
-    bool            forced_drm_fourcc;
-    uint32_t        drm_fourcc;
-
 /*
  * modeset information
  */
     uint32_t        plane_id;
 } vout_display_sys_t;
 
-/** fourccmatching, matching drm to vlc fourccs and see if it was present
- * in HW. Here really is two lists, one in RGB and second in YUV. They're
- * listed in order of preference.
- *
- * fourccmatching::drm DRM fourcc code from drm_fourcc.h
- * fourccmatching::plane_id from which plane this DRM fourcc was found
- * fourccmatching::present if this mode was available in HW
- * fourccmatching::isYUV as name suggest..
- */
-static struct
-{
-    uint32_t     drm;
-    bool         present;
-    bool         isYUV;
-} fourccmatching[] = {
-    { .drm = DRM_FORMAT_XRGB8888, .isYUV = false },
-    { .drm = DRM_FORMAT_RGB565, .isYUV = false },
-#if defined DRM_FORMAT_P010
-    { .drm = DRM_FORMAT_P010, .isYUV = true },
-#endif
-    { .drm = DRM_FORMAT_NV12, .isYUV = true },
-    { .drm = DRM_FORMAT_YUYV, .isYUV = true },
-    { .drm = DRM_FORMAT_YVYU, .isYUV = true },
-    { .drm = DRM_FORMAT_UYVY, .isYUV = true },
-    { .drm = DRM_FORMAT_VYUY, .isYUV = true },
-};
-
-
-static void CheckFourCCList(uint32_t drmfourcc)
-{
-    unsigned i;
-
-    for (i = 0; i < ARRAY_SIZE(fourccmatching); i++) {
-        if (fourccmatching[i].drm == drmfourcc) {
-            if (fourccmatching[i].present)
-                /* this drmfourcc already has a plane_id found where it
-                 * could be used, we'll stay with earlier findings.
-                 */
-                break;
-
-            fourccmatching[i].present = true;
-            break;
-        }
-    }
-}
-
-static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-    vout_window_t *wnd = vd->cfg->window;
-
-    unsigned i, c;
-    bool YUVFormat;
-
-    int drm_fd = wnd->display.drm_fd;
-
-    /*
-     * For convenience print out in debug prints all supported
-     * DRM modes so they can be seen if use verbose mode.
-     */
-    drmModePlane *plane = drmModeGetPlane(drm_fd, sys->plane_id);
-    if (plane != NULL) {
-        for (i = 0; i < plane->count_formats; i++)
-            CheckFourCCList(plane->formats[i]);
-        drmModeFreePlane(plane);
-    } else {
-        msg_Err(vd, "Couldn't get list of DRM formats");
-        return 0;
-    }
-
-    vlc_fourcc_t fourcc = vd->source->i_chroma;
-
-    if (sys->forced_drm_fourcc) {
-        for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-            if (fourccmatching[c].drm == sys->drm_fourcc) {
-                fourcc = vlc_fourcc_drm(sys->drm_fourcc);
-                break;
-            }
-        }
-        if (sys->plane_id == 0) {
-            msg_Err(vd, "Forced DRM fourcc (%.4s) not available in kernel.",
-                    (char*)&sys->drm_fourcc);
-            return 0;
-        }
-        return fourcc;
-    }
-
-    /*
-     * favor yuv format according to YUVFormat flag.
-     * check for exact match first, then YUVFormat and then !YUVFormat
-     */
-    uint_fast32_t drm_fourcc = vlc_drm_format(vd->source);
-
-    for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-        if (fourccmatching[c].drm == drm_fourcc) {
-            if (!sys->forced_drm_fourcc && fourccmatching[c].present)
-                sys->drm_fourcc = fourccmatching[c].drm;
-
-            if (!sys->drm_fourcc) {
-                msg_Err(vd, "Forced VLC fourcc (%.4s) not matching anything available in kernel, please set manually",
-                        (char*)&fourcc);
-                return 0;
-            }
-            return fourcc;
-        }
-    }
-
-    YUVFormat = vlc_fourcc_IsYUV(fourcc);
-    for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-        if (fourccmatching[c].isYUV == YUVFormat
-                && fourccmatching[c].present) {
-            if (!sys->forced_drm_fourcc)
-                sys->drm_fourcc = fourccmatching[c].drm;
-
-            return vlc_fourcc_drm(fourccmatching[c].drm);
-        }
-    }
-
-    for (i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-        if (!fourccmatching[c].isYUV != YUVFormat
-                && fourccmatching[c].present) {
-            if (!sys->forced_drm_fourcc)
-                sys->drm_fourcc = fourccmatching[c].drm;
-
-            return vlc_fourcc_drm(fourccmatching[c].drm);
-        }
-    }
-
-    return 0;
-}
-
 static int Control(vout_display_t *vd, int query)
 {
     (void) vd;
@@ -220,7 +82,6 @@ static int Control(vout_display_t *vd, int query)
     return VLC_EGENERIC;
 }
 
-
 static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
                     vlc_tick_t date)
 {
@@ -291,10 +152,8 @@ static int Open(vout_display_t *vd,
                 video_format_t *fmtp, vlc_video_context *context)
 {
     vout_window_t *wnd = vd->cfg->window;
-    vout_display_sys_t *sys;
-    uint32_t local_drm_chroma;
+    uint_fast32_t drm_fourcc = 0;
     video_format_t fmt;
-    char *chroma;
 
     if (wnd->type != VOUT_WINDOW_TYPE_KMS)
         return VLC_EGENERIC;
@@ -302,25 +161,15 @@ static int Open(vout_display_t *vd,
     /*
      * Allocate instance and initialize some members
      */
-    vd->sys = sys = vlc_obj_calloc(VLC_OBJECT(vd), 1, sizeof(*sys));
-    if (!sys)
+    vout_display_sys_t *sys = vlc_obj_malloc(VLC_OBJECT(vd), sizeof (*sys));
+    if (unlikely(sys == NULL))
         return VLC_ENOMEM;
 
-    chroma = var_InheritString(vd, "kms-drm-chroma");
+    char *chroma = var_InheritString(vd, "kms-drm-chroma");
     if (chroma) {
-        local_drm_chroma = VLC_FOURCC(chroma[0], chroma[1], chroma[2],
-                                      chroma[3]);
-
-        if (local_drm_chroma) {
-            sys->forced_drm_fourcc = true;
-            sys->drm_fourcc = local_drm_chroma;
-            msg_Dbg(vd, "Setting DRM chroma to '%4s'", chroma);
-        }
-        else
-            msg_Dbg(vd, "Chroma %4s invalid, using default", chroma);
-
+        memcpy(&drm_fourcc, chroma, strnlen(chroma, sizeof (drm_fourcc)));
+        msg_Dbg(vd, "Setting DRM chroma to '%4s'", chroma);
         free(chroma);
-        chroma = NULL;
     }
 
     int fd = wnd->display.drm_fd;
@@ -335,7 +184,8 @@ static int Open(vout_display_t *vd,
     msg_Dbg(vd, "using DRM CRTC object ID %"PRIu32", index %d",
             wnd->handle.crtc, crtc_index);
 
-    sys->plane_id = vlc_drm_get_crtc_primary_plane(fd, crtc_index);
+    size_t nfmt;
+    sys->plane_id = vlc_drm_get_crtc_primary_plane(fd, crtc_index, &nfmt);
     if (sys->plane_id == 0) {
         /* Most likely the window provider failed to set universal mode, or
          * failed to lease a primary plane. */
@@ -345,15 +195,26 @@ static int Open(vout_display_t *vd,
 
     msg_Dbg(vd, "using DRM plane ID %"PRIu32, sys->plane_id);
 
-    vlc_fourcc_t fourcc = ChromaNegotiation(vd);
-    if (!fourcc)
-        return VLC_EGENERIC;
+    if (drm_fourcc == 0) {
+        drm_fourcc = vlc_drm_find_best_format(fd, sys->plane_id, nfmt,
+                                              vd->fmt->i_chroma);
+        if (drm_fourcc == 0) {
+            msg_Err(vd, "DRM plane format error: %s", vlc_strerror_c(errno));
+            return -errno;
+        }
+    }
 
-    msg_Dbg(vd, "Using VLC chroma '%.4s', DRM chroma '%.4s'",
-            (char*)&fourcc, (char*)&sys->drm_fourcc);
+    msg_Dbg(vd, "using DRM pixel format %4.4s (0x%08"PRIXFAST32")",
+            (char *)&drm_fourcc, drm_fourcc);
 
     video_format_ApplyRotation(&fmt, vd->fmt);
-    fmt.i_chroma = fourcc;
+    if (!vlc_video_format_drm(&fmt, drm_fourcc)) {
+        /* This can only occur if $vlc-drm-chroma is unknown. */
+        assert(chroma != NULL);
+        msg_Err(vd, "unknown DRM pixel format %4.4s (0x%08"PRIXFAST32")",
+                (char *)&drm_fourcc, drm_fourcc);
+        return -ENOTSUP;
+    }
 
     for (size_t i = 0; i < ARRAY_SIZE(sys->buffers); i++) {
         sys->buffers[i] = vlc_drm_dumb_alloc_fb(vd->obj.logger, fd, &fmt);
@@ -364,7 +225,9 @@ static int Open(vout_display_t *vd,
         }
     }
 
+    sys->front_buf = 0;
     *fmtp = fmt;
+    vd->sys = sys;
     vd->ops = &ops;
 
     (void) context;


=====================================
modules/video_output/drm/fourcc.c
=====================================
@@ -225,8 +225,8 @@ uint_fast32_t vlc_drm_format(const video_format_t *restrict fmt)
     for (size_t i = 0; i < ARRAY_SIZE(rgb_fourcc_list); i++)
         if (rgb_fourcc_list[i].vlc_fourcc == fmt->i_chroma
          && rgb_fourcc_list[i].red == fmt->i_rmask
-         && rgb_fourcc_list[i].red == fmt->i_gmask
-         && rgb_fourcc_list[i].red == fmt->i_bmask)
+         && rgb_fourcc_list[i].green == fmt->i_gmask
+         && rgb_fourcc_list[i].blue == fmt->i_bmask)
             return rgb_fourcc_list[i].drm_fourcc;
 
     return DRM_FORMAT_INVALID;
@@ -244,3 +244,25 @@ vlc_fourcc_t vlc_fourcc_drm(uint_fast32_t drm_fourcc)
 
     return 0;
 }
+
+bool vlc_video_format_drm(video_format_t *restrict fmt,
+                          uint_fast32_t drm_fourcc)
+{
+    for (size_t i = 0; i < ARRAY_SIZE(fourcc_list); i++)
+        if (fourcc_list[i].drm_fourcc == drm_fourcc) {
+            fmt->i_chroma = fourcc_list[i].vlc_fourcc;
+            fmt->i_rmask = fmt->i_gmask = fmt->i_bmask = 0;
+            return true;
+        }
+
+    for (size_t i = 0; i < ARRAY_SIZE(rgb_fourcc_list); i++)
+        if (rgb_fourcc_list[i].drm_fourcc == drm_fourcc) {
+            fmt->i_chroma = rgb_fourcc_list[i].vlc_fourcc;
+            fmt->i_rmask = rgb_fourcc_list[i].red;
+            fmt->i_gmask = rgb_fourcc_list[i].green;
+            fmt->i_bmask = rgb_fourcc_list[i].blue;
+            return true;
+        }
+
+    return false;
+}


=====================================
modules/video_output/drm/planes.c
=====================================
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <drm_mode.h>
 #include <vlc_common.h>
+#include <vlc_fourcc.h>
 #include "vlc_drm.h"
 
 enum { /* DO NOT CHANGE. MUST MATCH KERNEL ABI. */
@@ -162,7 +163,8 @@ static ssize_t vlc_drm_get_planes(int fd, uint32_t **restrict listp)
     }
 }
 
-uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx)
+uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx,
+                                             size_t *restrict nfmt)
 {
     assert(idx < 32); /* Don't mix up object IDs and indices! */
 
@@ -184,6 +186,7 @@ uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx)
          && vlc_drm_get_plane_prop(fd, planes[i], "type", &planetype) == 0
          && planetype == VLC_DRM_PLANE_TYPE_PRIMARY) {
             ret = planes[i];
+            *nfmt = plane.count_format_types;
             goto out;
         }
     }
@@ -192,3 +195,66 @@ out:
     free(planes);
     return ret;
 }
+
+static uint_fast32_t vlc_drm_find_format(vlc_fourcc_t vlc_fourcc, size_t n,
+                                         const uint32_t *restrict drm_fourccs)
+{
+    assert(vlc_fourcc != 0);
+
+    const uint_fast32_t drm_fourcc = vlc_drm_fourcc(vlc_fourcc);
+
+    if (drm_fourcc != 0) {
+        /* Linear search for YUV(A) and RGBA formats */
+        for (size_t i = 0; i < n; i++)
+            if (drm_fourccs[i] == drm_fourcc)
+                return drm_fourcc;
+    }
+
+    /* Quadratic search for RGB formats */
+    for (size_t i = 0; i < n; i++)
+        if (vlc_fourcc_drm(drm_fourccs[i]) == vlc_fourcc)
+            return drm_fourccs[i];
+
+     return 0;
+}
+
+uint_fast32_t vlc_drm_find_best_format(int fd, uint_fast32_t plane_id,
+                                       size_t nfmt, vlc_fourcc_t chroma)
+{
+    uint32_t *fmts = vlc_alloc(nfmt, sizeof (*fmts));
+    if (unlikely(fmts == NULL))
+        return 0;
+
+    struct drm_mode_get_plane plane = {
+        .plane_id = plane_id,
+        .count_format_types = nfmt,
+        .format_type_ptr = (uintptr_t)(void *)fmts,
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPLANE, &plane) < 0) {
+        free(fmts);
+        return 0;
+    }
+
+    if (nfmt > plane.count_format_types)
+        nfmt = plane.count_format_types;
+
+    /* Look for an exact match first */
+    uint_fast32_t drm_fourcc = vlc_drm_find_format(chroma, nfmt, fmts);
+    if (drm_fourcc != 0)
+        goto out;
+
+    /* Fallback to decreasingly optimal formats */
+    const vlc_fourcc_t *list = vlc_fourcc_GetFallback(chroma);
+    assert(list != NULL);
+
+    for (size_t i = 0; list[i] != 0; i++) {
+        drm_fourcc = vlc_drm_find_format(list[i], nfmt, fmts);
+        if (drm_fourcc != 0)
+            goto out;
+    }
+    errno = ENOTSUP;
+out:
+    free(fmts);
+    return drm_fourcc;
+}


=====================================
modules/video_output/drm/vlc_drm.h
=====================================
@@ -24,6 +24,7 @@
 #endif
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/ioctl.h>
 #include <vlc_common.h>
@@ -62,6 +63,17 @@ uint_fast32_t vlc_drm_format(const struct video_format_t *fmt);
  */
 vlc_fourcc_t vlc_fourcc_drm(uint_fast32_t drm_fourcc);
 
+/**
+ * Converts a DRM pixel format to a VLC video format.
+ *
+ * \param [in,out] fmt VLC video format
+ * \param drm_fourcc DRM pixel format identifier
+ * \retval true the conversion succeeded (i.e. DRM format is recognised)
+ * \retval false the conversion failed (i.e. DRM format is unknown)
+ */
+bool vlc_video_format_drm(video_format_t *restrict fmt,
+                          uint_fast32_t drm_fourcc);
+
 /**
  * Allocates a DRM dumb buffer.
  *
@@ -102,9 +114,26 @@ int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id);
  *
  * \param fd DRM device file descriptor
  * \param idx CRTC object index (as returned by vlc_drm_get_crtc_index())
+ * }param[out] nfmts storage space for the plane's count of pixel formats
  * \return the primary plane object ID or zero on error
  */
-uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx);
+uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx,
+                                             size_t *nfmts);
+
+/**
+ * Finds the best matching DRM format.
+ *
+ * This determines the DRM format of a plane given by ID, which best matches
+ * a given VLC pixel format. If there is an exact match, it will be returned.
+ *
+ * \param fd DRM device file descriptor
+ * \param plane_id DRM plane object ID
+ * \param nfmt number of DRM pixel formats for the plane
+ * \param chroma VLC pixel format to match
+ * \return the matched DRM format on success, zero on failure
+ */
+uint_fast32_t vlc_drm_find_best_format(int fd, uint_fast32_t plane_id,
+                                       size_t nfmt, vlc_fourcc_t chroma);
 
 static inline int vlc_drm_ioctl(int fd, unsigned long cmd, void *argp)
 {



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f1a9cf187b4a66cf9cbef76e6cdc514f8a6303a2...eca00803d06cf436c214a7f51ec77e3743e0425b

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f1a9cf187b4a66cf9cbef76e6cdc514f8a6303a2...eca00803d06cf436c214a7f51ec77e3743e0425b
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list