[vlc-commits] [Git][videolan/vlc][master] 4 commits: drm: add trivial wrapper for DRM ioctl()

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Tue Mar 15 18:55:57 UTC 2022



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
1c4a6484 by Rémi Denis-Courmont at 2022-03-15T17:35:13+00:00
drm: add trivial wrapper for DRM ioctl()

- - - - -
03c5c6df by Rémi Denis-Courmont at 2022-03-15T17:35:13+00:00
drm: helpers for dumb buffers as pictures

- - - - -
50a0bc43 by Rémi Denis-Courmont at 2022-03-15T17:35:13+00:00
drm: use the buffer allocation helpers

This rectifies ioctl parameters so that allocating frame buffers no
longer fails in kernel.

This also cleans up the triple-buffered frame buffer handling:
now we keep one picture buffer for each of the 3 front buffers, instead
of switching the property of a dummy picture all the time.

- - - - -
aed74ede by Rémi Denis-Courmont at 2022-03-15T17:35:13+00:00
drm: remove redundant initialisation

- - - - -


4 changed files:

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


Changes:

=====================================
modules/video_output/Makefile.am
=====================================
@@ -321,6 +321,7 @@ libkms_plugin_la_LIBADD = $(KMS_LIBS)
 libdrm_display_plugin_la_SOURCES = \
 	video_output/drm/vlc_drm.h \
 	video_output/drm/fourcc.c \
+	video_output/drm/buffers.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/buffers.c
=====================================
@@ -0,0 +1,186 @@
+/**
+ * @file buffers.c
+ * @brief DRM dumb buffers
+ */
+/*****************************************************************************
+ * 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 <stdlib.h>
+#include <sys/mman.h>
+#include <drm_fourcc.h>
+#include <drm_mode.h>
+#include <vlc_common.h>
+#include <vlc_picture.h>
+#include "vlc_drm.h"
+
+struct vlc_drm_buf {
+    struct picture_buffer_t buf; /**< Common picture buffer properties */
+    uint32_t handle; /**< DRM buffer handle */
+    uint32_t fb_id; /**< DRM frame buffer identifier */
+};
+
+static void drmDestroyDumb(int fd, uint32_t handle)
+{
+    struct drm_mode_destroy_dumb dreq = {
+        .handle = handle,
+    };
+
+    vlc_drm_ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);
+}
+
+static void vlc_drm_dumb_buf_destroy(struct vlc_drm_buf *picbuf)
+{
+    munmap(picbuf->buf.base, picbuf->buf.size);
+    drmDestroyDumb(picbuf->buf.fd, picbuf->handle);
+    free(picbuf);
+}
+
+static void vlc_drm_dumb_destroy(picture_t *pic)
+{
+    struct vlc_drm_buf *picbuf = pic->p_sys;
+
+    if (picbuf->fb_id != 0)
+        vlc_drm_ioctl(picbuf->buf.fd, DRM_IOCTL_MODE_RMFB, &picbuf->fb_id);
+
+    vlc_drm_dumb_buf_destroy(picbuf);
+}
+
+picture_t *vlc_drm_dumb_alloc(struct vlc_logger *log, int fd,
+                              const video_format_t *restrict fmt)
+{
+    picture_t template;
+
+    if (picture_Setup(&template, fmt))
+        return NULL;
+
+    /* Create the buffer handle */
+    struct drm_mode_create_dumb creq = {
+        .height = template.format.i_height,
+        .width = template.format.i_width,
+        .bpp = (template.format.i_bits_per_pixel + 7) & ~7,
+        .flags =  0,
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq) < 0) {
+        vlc_error(log, "DRM dumb buffer creation error: %s",
+                  vlc_strerror(errno));
+        return NULL;
+    }
+
+    /* Map (really allocate) the buffer on driver side */
+    struct drm_mode_map_dumb mreq = {
+        .handle = creq.handle,
+    };
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq) < 0) {
+        vlc_error(log, "DRM dumb buffer mapping setup error: %s",
+                  vlc_strerror(errno));
+error:  drmDestroyDumb(fd, creq.handle);
+        return NULL;
+    }
+
+    /* Map the buffer into the application process */
+    unsigned char *base = mmap(NULL, creq.size, PROT_READ | PROT_WRITE,
+                               MAP_SHARED, fd, mreq.offset);
+    if (base == MAP_FAILED) {
+        vlc_error(log, "DRM dumb buffer memory-mapping error: %s",
+                  vlc_strerror(errno));
+        goto error;
+    }
+
+    /* Create the VLC picture representation */
+    struct vlc_drm_buf *picbuf = malloc(sizeof (*picbuf));
+    if (unlikely(picbuf == NULL)) {
+        munmap(base, creq.size);
+        goto error;
+    }
+
+    picbuf->buf.fd = fd;
+    picbuf->buf.base = base;
+    picbuf->buf.size = creq.size;
+    picbuf->buf.offset = mreq.offset;
+    picbuf->handle = creq.handle;
+    picbuf->fb_id = 0;
+
+    picture_resource_t res = {
+        .p_sys = picbuf,
+        .pf_destroy = vlc_drm_dumb_destroy,
+    };
+
+    for (int i = 0; i < template.i_planes; i++) {
+        res.p[i].p_pixels = base;
+        res.p[i].i_lines = template.p[i].i_lines;
+        res.p[i].i_pitch = template.p[i].i_pitch;
+        base += template.p[i].i_lines * template.p[i].i_pitch;
+    }
+
+    picture_t *pic = picture_NewFromResource(fmt, &res);
+    if (unlikely(pic == NULL))
+        vlc_drm_dumb_buf_destroy(picbuf);
+    return pic;
+}
+
+picture_t *vlc_drm_dumb_alloc_fb(struct vlc_logger *log, int fd,
+                                 const video_format_t *restrict fmt)
+{
+    uint32_t pixfmt = vlc_drm_format(fmt);
+    if (pixfmt == DRM_FORMAT_INVALID)
+        return NULL;
+
+    picture_t *pic = vlc_drm_dumb_alloc(log, fd, fmt);
+    if (pic == NULL)
+        return NULL;
+
+    struct vlc_drm_buf *picbuf = pic->p_sys;
+    struct drm_mode_fb_cmd2 cmd = {
+        .width = fmt->i_width,
+        .height = fmt->i_height,
+        .pixel_format = pixfmt,
+        .flags = 0,
+    };
+
+    for (int i = 0; i < pic->i_planes; i++)
+        cmd.handles[i] = picbuf->handle;
+    for (int i = 0; i < pic->i_planes; i++)
+        cmd.pitches[i] = pic->p[i].i_pitch;
+    for (int i = 1; i < pic->i_planes; i++)
+        cmd.offsets[i] = pic->p[i].p_pixels - pic->p[0].p_pixels;
+
+    if (vlc_drm_ioctl(fd, DRM_IOCTL_MODE_ADDFB2, &cmd) < 0) {
+        vlc_error(log, "DRM framebuffer addition error: %s",
+                  vlc_strerror(errno));
+        picture_Release(pic);
+        pic = NULL;
+    } else
+        picbuf->fb_id = cmd.fb_id;
+
+    return pic;
+}
+
+uint32_t vlc_drm_dumb_get_fb_id(const picture_t *pic)
+{
+    struct vlc_drm_buf *picbuf = pic->p_sys;
+
+    assert(picbuf->fb_id != 0);
+    return picbuf->fb_id;
+}


=====================================
modules/video_output/drm/display.c
=====================================
@@ -32,9 +32,6 @@
 # include "config.h"
 #endif
 
-#include <fcntl.h>
-#include <sys/mman.h>
-
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 #include <drm_fourcc.h>
@@ -42,8 +39,7 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_vout_display.h>
-#include <vlc_picture_pool.h>
-#include <vlc_fs.h>
+#include <vlc_picture.h>
 #include <vlc_vout_window.h>
 #include "vlc_drm.h"
 
@@ -65,20 +61,7 @@ typedef enum { drvSuccess, drvTryNext, drvFail } deviceRval;
 #define   MAXHWBUF 3
 
 typedef struct vout_display_sys_t {
-/*
- * buffer information
- */
-    uint32_t        width;
-    uint32_t        height;
-    uint32_t        stride;
-    uint32_t        size;
-    uint32_t        offsets[PICTURE_PLANE_MAX];
-
-    uint32_t        handle[MAXHWBUF];
-    uint8_t         *map[MAXHWBUF];
-
-    uint32_t        fb[MAXHWBUF];
-    picture_t       *picture;
+    picture_t       *buffers[MAXHWBUF];
 
     unsigned int    front_buf;
 
@@ -91,124 +74,6 @@ typedef struct vout_display_sys_t {
     uint32_t        plane_id;
 } vout_display_sys_t;
 
-static void DestroyFB(vout_display_t *vd, uint32_t const buf)
-{
-    struct vout_window_t *wnd = vd->cfg->window;
-    vout_display_sys_t *sys = vd->sys;
-    int drm_fd = wnd->display.drm_fd;
-
-    struct drm_mode_destroy_dumb destroy_req = { .handle = sys->handle[buf] };
-
-    munmap(sys->map[buf], sys->size);
-    drmModeRmFB(drm_fd, sys->fb[buf]);
-    drmIoctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
-}
-
-static deviceRval CreateFB(vout_display_t *vd, const int buf)
-{
-    struct vout_window_t *wnd = vd->cfg->window;
-    vout_display_sys_t *sys = vd->sys;
-    int drm_fd = wnd->display.drm_fd;
-
-    struct drm_mode_create_dumb create_req = { .width = sys->width,
-                                               .height = sys->height,
-                                               .bpp = 32 };
-    struct drm_mode_destroy_dumb destroy_req;
-    struct drm_mode_map_dumb modify_req = {};
-    unsigned int tile_width = 512, tile_height = 16;
-    deviceRval ret;
-    uint32_t i;
-    uint32_t offsets[] = {0,0,0,0}, handles[] = {0,0,0,0},
-            pitches[] = {0,0,0,0};
-
-    switch(sys->drm_fourcc) {
-#ifdef DRM_FORMAT_P010
-    case DRM_FORMAT_P010:
-#endif
-#ifdef DRM_FORMAT_P012
-    case DRM_FORMAT_P012:
-#endif
-#ifdef DRM_FORMAT_P016
-    case DRM_FORMAT_P016:
-#endif
-#if defined(DRM_FORMAT_P010) || defined(DRM_FORMAT_P012) || defined(DRM_FORMAT_P016)
-        sys->stride = vlc_align(sys->width*2, tile_width);
-        sys->offsets[1] = sys->stride*vlc_align(sys->height, tile_height);
-        create_req.height = 2*vlc_align(sys->height, tile_height);
-        break;
-#endif
-    case DRM_FORMAT_NV12:
-        sys->stride = vlc_align(sys->width, tile_width);
-        sys->offsets[1] = sys->stride*vlc_align(sys->height, tile_height);
-        create_req.height = 2*vlc_align(sys->height, tile_height);
-        break;
-    default:
-        create_req.height = vlc_align(sys->height, tile_height);
-
-        /*
-         * width *4 so there's enough space for anything.
-         */
-        sys->stride = vlc_align(sys->width*4, tile_width);
-        break;
-    }
-
-    ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req);
-    if (ret < 0) {
-        msg_Err(vd, "Cannot create dumb buffer");
-        return drvFail;
-    }
-
-    sys->size = create_req.size;
-    sys->handle[buf] = create_req.handle;
-
-    /*
-     * create framebuffer object for the dumb-buffer
-     * index 0 has to be filled in any case.
-     */
-    for (i = 0; i < ARRAY_SIZE(handles) && (sys->offsets[i] || i < 1); i++) {
-        handles[i] = create_req.handle;
-        pitches[i] = sys->stride;
-        offsets[i] = sys->offsets[i];
-    }
-
-    ret = drmModeAddFB2(drm_fd, sys->width, sys->height, sys->drm_fourcc,
-                        handles, pitches, offsets, &sys->fb[buf], 0);
-
-    if (ret) {
-        msg_Err(vd, "Cannot create frame buffer");
-        ret = drvFail;
-        goto err_destroy;
-    }
-
-    modify_req.handle = sys->handle[buf];
-    ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &modify_req);
-    if (ret) {
-        msg_Err(vd, "Cannot map dumb buffer");
-        ret = drvFail;
-        goto err_fb;
-    }
-
-    sys->map[buf] = mmap(0, sys->size, PROT_READ | PROT_WRITE, MAP_SHARED,
-                         drm_fd, modify_req.offset);
-
-    if (sys->map[buf] == MAP_FAILED) {
-        msg_Err(vd, "Cannot mmap dumb buffer");
-        ret = drvFail;
-        goto err_fb;
-    }
-    return drvSuccess;
-
-err_fb:
-    drmModeRmFB(drm_fd, sys->fb[buf]);
-    sys->fb[buf] = 0;
-
-err_destroy:
-    memset(&destroy_req, 0, sizeof(destroy_req));
-    destroy_req.handle = sys->handle[buf];
-    drmIoctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
-    return ret;
-}
-
 /** 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.
@@ -423,12 +288,6 @@ static vlc_fourcc_t ChromaNegotiation(vout_display_t *vd)
     return 0;
 }
 
-static void CustomDestroyPicture(vout_display_t *vd)
-{
-    for (int c = 0; c < MAXHWBUF; c++)
-        DestroyFB(vd, c);
-}
-
 static int Control(vout_display_t *vd, int query)
 {
     (void) vd;
@@ -450,7 +309,8 @@ static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
 {
     VLC_UNUSED(subpic); VLC_UNUSED(date);
     vout_display_sys_t *sys = vd->sys;
-    picture_Copy( sys->picture, pic );
+
+    picture_Copy(sys->buffers[sys->front_buf], pic);
 }
 
 static void Display(vout_display_t *vd, picture_t *picture)
@@ -458,30 +318,28 @@ static void Display(vout_display_t *vd, picture_t *picture)
     VLC_UNUSED(picture);
     vout_display_sys_t *sys = vd->sys;
     vout_window_t *wnd = vd->cfg->window;
+    picture_t *pic = sys->buffers[sys->front_buf];
+    uint32_t fb_id = vlc_drm_dumb_get_fb_id(pic);
 
     vout_display_place_t place;
     vout_display_PlacePicture(&place, vd->fmt, vd->cfg);
 
     int ret = drmModeSetPlane(wnd->display.drm_fd,
-            sys->plane_id, wnd->handle.crtc, sys->fb[sys->front_buf], 0,
+            sys->plane_id, wnd->handle.crtc, fb_id, 0,
             place.x, place.y, place.width, place.height,
             vd->fmt->i_x_offset << 16, vd->fmt->i_y_offset << 16,
             vd->fmt->i_visible_width << 16, vd->fmt->i_visible_height << 16);
     if (ret != drvSuccess)
     {
-        msg_Err(vd, "Cannot do set plane for plane id %u, fb %x",
-                sys->plane_id,
-                sys->fb[sys->front_buf]);
+        msg_Err(vd, "Cannot do set plane for plane id %u, fb %"PRIu32,
+                sys->plane_id, fb_id);
         assert(ret != -EINVAL);
         return;
     }
 
     sys->front_buf++;
-    sys->front_buf %= MAXHWBUF;
-
-    for (int i = 0; i < PICTURE_PLANE_MAX; i++)
-        sys->picture->p[i].p_pixels =
-                sys->map[sys->front_buf]+sys->offsets[i];
+    if (sys->front_buf == MAXHWBUF)
+        sys->front_buf = 0;
 }
 
 /**
@@ -491,10 +349,8 @@ static void Close(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    if (sys->picture)
-        picture_Release(sys->picture);
-    CustomDestroyPicture(vd);
-
+    for (size_t i = 0; i < ARRAY_SIZE(sys->buffers); i++)
+        picture_Release(sys->buffers[i]);
 }
 
 static const struct vlc_display_operations ops = {
@@ -512,7 +368,7 @@ static int Open(vout_display_t *vd,
 {
     vout_display_sys_t *sys;
     uint32_t local_drm_chroma;
-    video_format_t fmt = {};
+    video_format_t fmt;
     char *chroma;
 
     if (vd->cfg->window->type != VOUT_WINDOW_TYPE_KMS)
@@ -542,43 +398,24 @@ static int Open(vout_display_t *vd,
         chroma = NULL;
     }
 
+    int fd = vd->cfg->window->display.drm_fd;
     vlc_fourcc_t fourcc = ChromaNegotiation(vd);
-    if (!fourcc) {
-        Close(vd);
+    if (!fourcc)
         return VLC_EGENERIC;
-    }
 
     msg_Dbg(vd, "Using VLC chroma '%.4s', DRM chroma '%.4s'",
             (char*)&fourcc, (char*)&sys->drm_fourcc);
 
     video_format_ApplyRotation(&fmt, vd->fmt);
-
-    sys->width  = fmt.i_visible_width;
-    sys->height = fmt.i_visible_height;
-
-    for (int c = 0; c < MAXHWBUF; c++) {
-        int ret = CreateFB(vd, c);
-        if (ret != drvSuccess) {
-            for (int c2 = 0; c2 < c; c2++)
-                DestroyFB(vd, c2);
-            return ret;
-        }
-    }
-
-    picture_resource_t rsc = { 0 };
-    fmt.i_width = fmt.i_visible_width  = sys->width;
-    fmt.i_height = fmt.i_visible_height = sys->height;
     fmt.i_chroma = fourcc;
 
-    sys->picture = picture_NewFromResource(&fmt, &rsc);
-
-    if (!sys->picture)
-        goto error;
-
-    for (size_t i = 0; i < PICTURE_PLANE_MAX; i++) {
-        sys->picture->p[i].p_pixels = sys->map[0] + sys->offsets[i];
-        sys->picture->p[i].i_lines  = sys->height;
-        sys->picture->p[i].i_pitch  = sys->stride;
+    for (size_t i = 0; i < ARRAY_SIZE(sys->buffers); i++) {
+        sys->buffers[i] = vlc_drm_dumb_alloc_fb(vd->obj.logger, fd, &fmt);
+        if (sys->buffers[i] == NULL) {
+            while (i > 0)
+                picture_Release(sys->buffers[--i]);
+            return -ENOBUFS;
+        }
     }
 
     *fmtp = fmt;
@@ -586,9 +423,6 @@ static int Open(vout_display_t *vd,
 
     (void) context;
     return VLC_SUCCESS;
-
-error:
-    return VLC_EGENERIC;
 }
 
 /*****************************************************************************


=====================================
modules/video_output/drm/vlc_drm.h
=====================================
@@ -23,9 +23,12 @@
 # include <config.h>
 #endif
 
+#include <errno.h>
 #include <stdint.h>
+#include <sys/ioctl.h>
 #include <vlc_common.h>
 
+struct vlc_logger;
 struct video_format_t;
 
 /**
@@ -58,3 +61,36 @@ uint_fast32_t vlc_drm_format(const struct video_format_t *fmt);
  * \return the corresponding VLC pixel format, or 0 if not found.
  */
 vlc_fourcc_t vlc_fourcc_drm(uint_fast32_t drm_fourcc);
+
+/**
+ * Allocates a DRM dumb buffer.
+ *
+ * \param fd DRM device file descriptor
+ * \param fmt picture format
+ * \return a DRM dumb frame buffer as picture, or NULL on error.
+ */
+picture_t *vlc_drm_dumb_alloc(struct vlc_logger *, int fd,
+                              const video_format_t *restrict fmt);
+
+/**
+ * Allocates a DRM dumb frame buffer.
+ *
+ * \param fd DRM device file descriptor
+ * \param fmt picture format
+ * \return a DRM dumb frame buffer as picture, or NULL on error.
+ */
+picture_t *vlc_drm_dumb_alloc_fb(struct vlc_logger *, int fd,
+                                 const video_format_t *restrict fmt);
+
+uint32_t vlc_drm_dumb_get_fb_id(const picture_t *pic);
+
+static inline int vlc_drm_ioctl(int fd, unsigned long cmd, void *argp)
+{
+    int ret;
+
+    do
+        ret = ioctl(fd, cmd, argp);
+    while (ret < 0 && (errno == EINTR || errno == EAGAIN));
+
+    return ret;
+}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/6b4b7225e5ba757ecc4ca38eb6de2e21a43a9c6d...aed74edea926e985c42257475a757169a58ea7f6

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