[vlc-commits] [Git][videolan/vlc][master] 4 commits: drm: add helper to find the CRTC index

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Wed Mar 23 17:31:39 UTC 2022



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


Commits:
86a84951 by Rémi Denis-Courmont at 2022-03-23T16:57:10+00:00
drm: add helper to find the CRTC index

(for matching planes to the CRTC)

- - - - -
82056aa6 by Rémi Denis-Courmont at 2022-03-23T16:57:10+00:00
drm: use the CRTC index helper

- - - - -
3aa95369 by Rémi Denis-Courmont at 2022-03-23T16:57:10+00:00
drm: helper to get the primary plane

- - - - -
ee3f780e by Rémi Denis-Courmont at 2022-03-23T16:57:10+00:00
drm: always use the primary plane

The code used the first plane that matched the wanted pixel format.
This has mostly been working as the primary plane is normally the first
plane, but it incorrectly assumed that other plane types would not
expose further pixel formats, or that VLC would not prefer any of them.

- - - - -


4 changed files:

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


Changes:

=====================================
modules/video_output/Makefile.am
=====================================
@@ -324,6 +324,7 @@ libdrm_display_plugin_la_SOURCES = \
 	video_output/drm/vlc_drm.h \
 	video_output/drm/fourcc.c \
 	video_output/drm/buffers.c \
+	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)


=====================================
modules/video_output/drm/display.c
=====================================
@@ -86,7 +86,6 @@ typedef struct vout_display_sys_t {
 static struct
 {
     uint32_t     drm;
-    uint32_t     plane_id;
     bool         present;
     bool         isYUV;
 } fourccmatching[] = {
@@ -103,7 +102,7 @@ static struct
 };
 
 
-static void CheckFourCCList(uint32_t drmfourcc, uint32_t plane_id)
+static void CheckFourCCList(uint32_t drmfourcc)
 {
     unsigned i;
 
@@ -116,7 +115,6 @@ static void CheckFourCCList(uint32_t drmfourcc, uint32_t plane_id)
                 break;
 
             fourccmatching[i].present = true;
-            fourccmatching[i].plane_id = plane_id;
             break;
         }
     }
@@ -128,60 +126,22 @@ static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
     vout_window_t *wnd = vd->cfg->window;
 
     unsigned i, c;
-    drmModePlaneRes *plane_res = NULL;
-    drmModePlane *plane;
     bool YUVFormat;
 
     int drm_fd = wnd->display.drm_fd;
 
-    drmModeRes *resources = drmModeGetResources(drm_fd);
-    if (resources == NULL)
-        return 0;
-
-    int crtc_index = -1;
-    for (int crtc_id=0; crtc_id < resources->count_crtcs; ++crtc_id)
-    {
-        if (resources->crtcs[crtc_id] == wnd->handle.crtc)
-        {
-            crtc_index = crtc_id;
-            break;
-        }
-    }
-    drmModeFreeResources(resources);
-
     /*
      * For convenience print out in debug prints all supported
      * DRM modes so they can be seen if use verbose mode.
      */
-    plane_res = drmModeGetPlaneResources(drm_fd);
-    sys->plane_id = 0;
-
-    if (plane_res != NULL && plane_res->count_planes > 0) {
-        for (c = 0; c < plane_res->count_planes; c++) {
-            plane = drmModeGetPlane(drm_fd, plane_res->planes[c]);
-            if (plane != NULL && plane->count_formats > 0) {
-                if ((plane->possible_crtcs & (1 << crtc_index)) == 0)
-                {
-                    drmModeFreePlane(plane);
-                    continue;
-                }
-
-                for (i = 0; i < plane->count_formats; i++) {
-                    CheckFourCCList(plane->formats[i], plane->plane_id);
-
-                    if (sys->forced_drm_fourcc && sys->plane_id == 0 &&
-                            plane->formats[i] == sys->drm_fourcc) {
-                        sys->plane_id = plane->plane_id;
-                    }
-                }
-                drmModeFreePlane(plane);
-            } else {
-                msg_Err(vd, "Couldn't get list of DRM formats");
-                drmModeFreePlaneResources(plane_res);
-                return 0;
-            }
-        }
-        drmModeFreePlaneResources(plane_res);
+    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;
@@ -209,10 +169,8 @@ static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
 
     for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
         if (fourccmatching[c].drm == drm_fourcc) {
-            if (!sys->forced_drm_fourcc && fourccmatching[c].present) {
+            if (!sys->forced_drm_fourcc && fourccmatching[c].present)
                 sys->drm_fourcc = fourccmatching[c].drm;
-                sys->plane_id = fourccmatching[c].plane_id;
-             }
 
             if (!sys->drm_fourcc) {
                 msg_Err(vd, "Forced VLC fourcc (%.4s) not matching anything available in kernel, please set manually",
@@ -227,10 +185,8 @@ static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
     for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
         if (fourccmatching[c].isYUV == YUVFormat
                 && fourccmatching[c].present) {
-            if (!sys->forced_drm_fourcc) {
+            if (!sys->forced_drm_fourcc)
                 sys->drm_fourcc = fourccmatching[c].drm;
-                sys->plane_id = fourccmatching[c].plane_id;
-             }
 
             return vlc_fourcc_drm(fourccmatching[c].drm);
         }
@@ -239,10 +195,8 @@ static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
     for (i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
         if (!fourccmatching[c].isYUV != YUVFormat
                 && fourccmatching[c].present) {
-            if (!sys->forced_drm_fourcc) {
+            if (!sys->forced_drm_fourcc)
                 sys->drm_fourcc = fourccmatching[c].drm;
-                sys->plane_id = fourccmatching[c].plane_id;
-             }
 
             return vlc_fourcc_drm(fourccmatching[c].drm);
         }
@@ -336,12 +290,13 @@ static const struct vlc_display_operations ops = {
 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;
     video_format_t fmt;
     char *chroma;
 
-    if (vd->cfg->window->type != VOUT_WINDOW_TYPE_KMS)
+    if (wnd->type != VOUT_WINDOW_TYPE_KMS)
         return VLC_EGENERIC;
 
     /*
@@ -368,7 +323,28 @@ static int Open(vout_display_t *vd,
         chroma = NULL;
     }
 
-    int fd = vd->cfg->window->display.drm_fd;
+    int fd = wnd->display.drm_fd;
+
+    int crtc_index = vlc_drm_get_crtc_index(fd, wnd->handle.crtc);
+    if (crtc_index < 0) {
+        msg_Err(vd, "DRM CRTC object ID %"PRIu32" error: %s",
+                wnd->handle.crtc, vlc_strerror_c(errno));
+        return -errno;
+    }
+
+    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);
+    if (sys->plane_id == 0) {
+        /* Most likely the window provider failed to set universal mode, or
+         * failed to lease a primary plane. */
+        msg_Err(vd, "DRM primary plane not found: %s", vlc_strerror_c(errno));
+        return -errno;
+    }
+
+    msg_Dbg(vd, "using DRM plane ID %"PRIu32, sys->plane_id);
+
     vlc_fourcc_t fourcc = ChromaNegotiation(vd);
     if (!fourcc)
         return VLC_EGENERIC;


=====================================
modules/video_output/drm/planes.c
=====================================
@@ -0,0 +1,194 @@
+/**
+ * @file planes.c
+ * @brief DRM planes
+ */
+/*****************************************************************************
+ * Copyright © 2022 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <drm_mode.h>
+#include <vlc_common.h>
+#include "vlc_drm.h"
+
+enum { /* DO NOT CHANGE. MUST MATCH KERNEL ABI. */
+    VLC_DRM_PLANE_TYPE_OVERLAY=0,
+    VLC_DRM_PLANE_TYPE_PRIMARY=1,
+    VLC_DRM_PLANE_TYPE_CURSOR=2,
+};
+
+int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id)
+{
+    uint32_t crtcs[32];
+    struct drm_mode_card_res res = {
+        .crtc_id_ptr = (uintptr_t)(void *)crtcs,
+        .count_crtcs = ARRAY_SIZE(crtcs),
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) < 0)
+        return -1;
+    if (unlikely(res.count_crtcs > ARRAY_SIZE(crtcs))) {
+        /* The API cannot deal with more than 32 CRTCs. Buggy driver? */
+        errno = ENOBUFS;
+        return -1;
+    }
+
+    for (size_t i = 0; i < res.count_crtcs; i++)
+        if (crtcs[i] == crtc_id)
+            return i;
+
+    errno = ENXIO;
+    return -1;
+}
+
+static bool vlc_drm_prop_match(int fd, uint_fast32_t pid, const char *name)
+{
+    struct drm_mode_get_property prop = {
+        .prop_id = pid,
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop) < 0)
+        return false;
+    return strcmp(name, prop.name) == 0;
+}
+
+static int vlc_drm_get_prop(int fd, uint_fast32_t oid, uint_fast32_t tid,
+                            const char *name, uint64_t *restrict valp)
+{
+    struct drm_mode_obj_get_properties counter = {
+        .obj_id = oid,
+        .obj_type = tid,
+    };
+    int ret = -1;
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &counter) < 0)
+        return -1;
+
+    size_t count = counter.count_props;
+    uint32_t *ids = vlc_alloc(count, sizeof (*ids));
+    uint64_t *values = vlc_alloc(count, sizeof (*values));
+
+    if (unlikely(ids == NULL || values == NULL))
+        goto out;
+
+    struct drm_mode_obj_get_properties props = {
+        .props_ptr = (uintptr_t)(void *)ids,
+        .prop_values_ptr = (uintptr_t)(void *)values,
+        .count_props = count,
+        .obj_id = oid,
+        .obj_type = tid,
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &props) < 0)
+        goto out;
+    if (unlikely(count < props.count_props)) {
+        /*
+         * Properties should not be created asynchronously. It could
+         * theoretically occur if the underlying object was hot-unplugged, then
+         * different object with the same type was hot-plugged and got the same
+         * object identifier. But if so, everything we thought we knew till now
+         * has potentially become invalid, so we might as well fail safely.
+         */
+        errno = ENOBUFS;
+        goto out;
+    }
+
+    /* NOTE: if more than one property is needed, rethink this function */
+    for (size_t i = 0; i < props.count_props; i++) {
+        if (vlc_drm_prop_match(fd, ids[i], name)) {
+            *valp = values[i];
+            ret = 0;
+            goto out;
+        }
+    }
+    errno = ENXIO;
+out:
+    free(values);
+    free(ids);
+    return ret;
+}
+
+static int vlc_drm_get_plane_prop(int fd, uint_fast32_t plane,
+                                  const char *name, uint64_t *restrict valp)
+{
+    return vlc_drm_get_prop(fd, plane, DRM_MODE_OBJECT_PLANE, name, valp);
+}
+
+static ssize_t vlc_drm_get_planes(int fd, uint32_t **restrict listp)
+{
+    size_t count = 32;
+
+    for (;;) {
+        uint32_t *planes = vlc_alloc(count, sizeof (*planes));
+        if (unlikely(planes == NULL))
+            return -1;
+
+        struct drm_mode_get_plane_res res = {
+            .plane_id_ptr = (uintptr_t)(void *)planes,
+            .count_planes = count,
+        };
+
+        if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res) < 0) {
+            free(planes);
+            return -1;
+        }
+
+        if (likely(count >= res.count_planes)) {
+            *listp = planes;
+            return res.count_planes;
+        }
+        free(planes);
+    }
+}
+
+uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx)
+{
+    assert(idx < 32); /* Don't mix up object IDs and indices! */
+
+    uint32_t *planes;
+    ssize_t count = vlc_drm_get_planes(fd, &planes);
+    if (count < 0)
+        return -1;
+
+    uint_fast32_t ret = 0;
+
+    for (ssize_t i = 0; i < count; i++) {
+        struct drm_mode_get_plane plane = {
+            .plane_id = planes[i],
+        };
+        uint64_t planetype;
+
+        if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_GETPLANE, &plane) >= 0
+         && ((plane.possible_crtcs >> idx) & 1)
+         && vlc_drm_get_plane_prop(fd, planes[i], "type", &planetype) == 0
+         && planetype == VLC_DRM_PLANE_TYPE_PRIMARY) {
+            ret = planes[i];
+            goto out;
+        }
+    }
+    errno = ENXIO;
+out:
+    free(planes);
+    return ret;
+}


=====================================
modules/video_output/drm/vlc_drm.h
=====================================
@@ -84,6 +84,28 @@ picture_t *vlc_drm_dumb_alloc_fb(struct vlc_logger *, int fd,
 
 uint32_t vlc_drm_dumb_get_fb_id(const picture_t *pic);
 
+/**
+ * Finds the index of a CRTC.
+ *
+ * The DRM API represents sets of CRTCs as 32-bit bit masks.
+ * This function determines the bit index of a given CRTC.
+ *
+ * \param fd DRM device file descriptor
+ * \param crtc_id CRTC object ID
+ * \return On success, the index (between 0 and 31) of object is returned,
+ * On error, -1 is returned and @c errno is set.
+ */
+int vlc_drm_get_crtc_index(int fd, uint_fast32_t crtc_id);
+
+/**
+ * Finds the primary plane of a CRTC.
+ *
+ * \param fd DRM device file descriptor
+ * \param idx CRTC object index (as returned by vlc_drm_get_crtc_index())
+ * \return the primary plane object ID or zero on error
+ */
+uint_fast32_t vlc_drm_get_crtc_primary_plane(int fd, unsigned int idx);
+
 static inline int vlc_drm_ioctl(int fd, unsigned long cmd, void *argp)
 {
     int ret;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ee23251ddfe74394e6c3aed85a92ee48ba50aa38...ee3f780e520b9445e528f1547a153b197ea725ed

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/ee23251ddfe74394e6c3aed85a92ee48ba50aa38...ee3f780e520b9445e528f1547a153b197ea725ed
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