[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