[vlc-commits] [Git][videolan/vlc][master] 17 commits: configure.ac: use PKG_HAVE_WITH_MODULES for kms

François Cartegnie (@fcartegnie) gitlab at videolan.org
Sat Jan 8 20:24:55 UTC 2022



François Cartegnie pushed to branch master at VideoLAN / VLC


Commits:
cb6880d7 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
configure.ac: use PKG_HAVE_WITH_MODULES for kms

It avoids using autoconf conditionals and defining -rpath manually, and
makes HAVE_KMS available in the Makefile.am.

- - - - -
24d7a104 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
include: vlc_vout_window: add new KMS window type

The new KMS window represents an output from the DRM subsystem into a
given connector through the specified CRTC, or in simpler term, an
output screen. It allows running a "window" even in the case where no
window manager are presents, but it also makes sense in windowed
environment thanks to DRM leasing features.

- - - - -
8cb9abbf by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: split KMS into vout window and vout display

Implement the vout window interface for the KMS module to allocate the
framebuffer once for multiple playback and split the connector selection
and KMS initialization and cleanup from the vout_display.

This is done as a submodule for now, the display module will actually be
splitted afterwards.

- - - - -
62319a9d by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
drm_display: split vout_display from kms.c file

KMS is really the windowing part, put DRM framebuffer vout display into
a separate file.

- - - - -
c2323ece by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: fix cleanup to previous state

The framebuffer from the previous KMS state was lost and not recoverable
once the KMS module exited. It was only possible to reset the state by
switching TTY and switching back to the one where KMS was used.

- - - - -
e7bd4152 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: rename --kms option into --kms-device

This is breaking the plugin option, but --kms is a really bad naming for
selecting the device it's rendering onto (is it the device file? the
connector?), and it would have been much better suited for enabling or
not the KMS window.

- - - - -
1027773f by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: simplify with early exit

Avoid additional indentation level by using early exit on error.

- - - - -
85891915 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: honor the place configuration

Apply the settings from the video output configuration, since KMS is
able to do rescaling and cropping.

- - - - -
d263a9c1 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: fix memory leak

- - - - -
28f8f7b7 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: improve the naming of connectors

- - - - -
2a8106a8 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: add support for --kms-connector option

Add an option, --kms-connector, to target an arbitrary connector instead
of using the first suitable connector available. This is an equivalent
to selecting the output screen in the VLC API.

- - - - -
c78dc6f3 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: abort early if drm is not available

This is not using drmAvailable() which only checks against minor=0,
since card0 might not be available or not support DRM while card1 might
support it and be selected by --kms-device.

In addition, print the debug information about the current underlying
DRM driver implementation used. Note that according to NVidia's DRM
documentation[^1]:

    DRM-NVDC does not populate the drmVersionPtr structure's date,
    major, minor, and patchlevel fields.

[^1]: https://docs.nvidia.com/jetson/l4t-graphics/group__direct__rendering__manager.html#gaabb52f28bfc81b9af64866f88131d513

- - - - -
bdf1d32b by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: use shift instead of ffs

Shifts is more usual and easier to read here.

- - - - -
2987ee05 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: match plane with CRTC

Not all planes can be used with every CRTC, and especially when there
are multiple connectors plugged. Check that the corresponding CRTC is
compatible with the plane we probed before selecting it.

This avoids drmModeSetPlane failing with invalid CRTC -EINVAL errors.

- - - - -
17cc375d by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: use DRM_DIR_NAME for /dev/dri path

The path to card* is different on Linux and on other systems like
some BSD ones supporting the DRM infrastructure.

- - - - -
6218609a by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
opengl: egl_gbm: use DRM_DIR_NAME for path

DRM_DIR_NAME can be different, for instance on OpenBSD.

- - - - -
2a491074 by Alexandre Janniaux at 2022-01-08T20:12:50+00:00
kms: handle output reporting

Reports the different available connectors when opening the KMS vout
window module, with naming like most Wayland compositors and DRM info
tools.

This does not implement hotplug support though.

- - - - -


7 changed files:

- configure.ac
- include/vlc_vout_window.h
- modules/video_output/Makefile.am
- + modules/video_output/drm_display.c
- modules/video_output/kms.c
- modules/video_output/opengl/Makefile.am
- modules/video_output/opengl/egl_display_gbm.c


Changes:

=====================================
configure.ac
=====================================
@@ -3586,7 +3586,7 @@ AC_CHECK_HEADER([linux/fb.h], [
 dnl
 dnl  Linux kernel mode setting module
 dnl
-PKG_ENABLE_MODULES_VLC([KMS], [], [libdrm >= 2.4.83], [Linux kernel mode setting output], [auto])
+PKG_HAVE_WITH_MODULES([KMS], [libdrm >= 2.4.83], [Linux kernel mode setting output], [auto])
 
 dnl
 dnl  libcaca plugin


=====================================
include/vlc_vout_window.h
=====================================
@@ -64,6 +64,7 @@ enum vout_window_type {
     VOUT_WINDOW_TYPE_ANDROID_NATIVE /**< Android native window */,
     VOUT_WINDOW_TYPE_WAYLAND /**< Wayland surface */,
     VOUT_WINDOW_TYPE_DCOMP /**< Win32 DirectComposition */,
+    VOUT_WINDOW_TYPE_KMS /**< DRM KMS CRTC */,
 };
 
 /**
@@ -383,6 +384,7 @@ typedef struct vout_window_t {
         void     *anativewindow; /**< Android native window */
         struct wl_surface *wl;   /**< Wayland surface (client pointer) */
         void     *dcomp_visual;  /**<  Win32 direct composition visual */
+        uint32_t crtc;           /**< KMS CRTC identifier */
     } handle;
 
     /** Display server (mandatory)
@@ -397,6 +399,7 @@ typedef struct vout_window_t {
         char     *x11; /**< X11 display string (NULL = use default) */
         struct wl_display *wl; /**< Wayland display (client pointer) */
         void* dcomp_device; /**< DirectComposition device */
+        int      drm_fd; /**< KMS DRM device */
     } display;
 
     const struct vout_window_operations *ops; /**< operations handled by the


=====================================
modules/video_output/Makefile.am
=====================================
@@ -317,9 +317,13 @@ vout_LTLIBRARIES += $(LTLIBfb)
 libkms_plugin_la_SOURCES = video_output/kms.c
 libkms_plugin_la_CFLAGS = $(AM_CFLAGS) $(KMS_CFLAGS)
 libkms_plugin_la_LIBADD = $(KMS_LIBS)
-libkms_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
-EXTRA_LTLIBRARIES += libkms_plugin.la
-vout_LTLIBRARIES += $(LTLIBkms)
+
+libdrm_display_plugin_la_SOURCES = 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
 
 
 ### Coloured ASCII art ###


=====================================
modules/video_output/drm_display.c
=====================================
@@ -0,0 +1,642 @@
+/*****************************************************************************
+ * kms_drm.c : Direct rendering management plugin for vlc
+ *****************************************************************************
+ * Copyright © 2018 Intel Corporation
+ * Copyright © 2021 Videolabs
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm_fourcc.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout_display.h>
+#include <vlc_picture_pool.h>
+#include <vlc_fs.h>
+#include <vlc_vout_window.h>
+
+#include <assert.h>
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+#define VLC_CHROMA_TEXT "Image format used by VLC"
+#define VLC_CHROMA_LONGTEXT "Chroma fourcc request to VLC for output format"
+
+#define DRM_CHROMA_TEXT "Image format used by DRM"
+#define DRM_CHROMA_LONGTEXT "Chroma fourcc override for DRM framebuffer format selection"
+
+typedef enum { drvSuccess, drvTryNext, drvFail } deviceRval;
+
+/*
+ * how many hw buffers are allocated for page flipping. I think
+ * 3 is enough so we shouldn't get unexpected stall from kernel.
+ */
+#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;
+
+    unsigned int    front_buf;
+
+    bool            forced_drm_fourcc;
+    uint32_t        drm_fourcc;
+    vlc_fourcc_t    vlc_fourcc;
+
+/*
+ * modeset information
+ */
+    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.
+ *
+ * fourccmatching::drm DRM fourcc code from drm_fourcc.h
+ * fourccmatching::vlc VLC fourcc code from vlc_fourcc.h under title 'Chromas'
+ * 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;
+    vlc_fourcc_t vlc;
+    uint32_t     plane_id;
+    bool         present;
+    bool         isYUV;
+} fourccmatching[] = {
+    { .drm = DRM_FORMAT_XRGB8888, .vlc = VLC_CODEC_RGB32, .isYUV = false },
+    { .drm = DRM_FORMAT_RGB565, .vlc = VLC_CODEC_RGB16, .isYUV = false },
+#if defined DRM_FORMAT_P010
+    { .drm = DRM_FORMAT_P010, .vlc = VLC_CODEC_P010, .isYUV = true },
+#endif
+    { .drm = DRM_FORMAT_NV12, .vlc = VLC_CODEC_NV12, .isYUV = true },
+    { .drm = DRM_FORMAT_YUYV, .vlc = VLC_CODEC_YUYV, .isYUV = true },
+    { .drm = DRM_FORMAT_YVYU, .vlc = VLC_CODEC_YVYU, .isYUV = true },
+    { .drm = DRM_FORMAT_UYVY, .vlc = VLC_CODEC_UYVY, .isYUV = true },
+    { .drm = DRM_FORMAT_VYUY, .vlc = VLC_CODEC_VYUY, .isYUV = true },
+};
+
+
+static void CheckFourCCList(uint32_t drmfourcc, uint32_t plane_id)
+{
+    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;
+            fourccmatching[i].plane_id = plane_id;
+            break;
+        }
+    }
+}
+
+
+static bool ChromaNegotiation(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+    vout_window_t *wnd = vd->cfg->window;
+
+    unsigned i, c, propi;
+    uint32_t planetype;
+    const char types[][16] = { "OVERLAY", "PRIMARY", "CURSOR", "UNKNOWN" };
+    drmModePlaneRes *plane_res = NULL;
+    drmModePlane *plane;
+    drmModeObjectProperties *props;
+    drmModePropertyPtr pp;
+    bool YUVFormat;
+
+    int drm_fd = wnd->display.drm_fd;
+
+    drmModeRes *resources = drmModeGetResources(drm_fd);
+    if (resources == NULL)
+        return false;
+
+    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) {
+        msg_Dbg(vd, "List of DRM supported modes on this machine:");
+        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;
+                }
+
+                props = drmModeObjectGetProperties(drm_fd,
+                                                   plane->plane_id,
+                                                   DRM_MODE_OBJECT_PLANE);
+
+                planetype = 3;
+                pp = NULL;
+                for (propi = 0; propi < props->count_props; propi++) {
+                    pp = drmModeGetProperty(drm_fd, props->props[propi]);
+                    if (strcmp(pp->name, "type") == 0) {
+                        break;
+                    }
+                    drmModeFreeProperty(pp);
+                }
+
+                if (pp != NULL) {
+                    drmModeFreeProperty(pp);
+                    planetype = props->prop_values[propi];
+                }
+
+                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;
+                    }
+
+                    /*
+                     * we don't advertise about cursor plane because
+                     * of its special limitations.
+                     */
+                    if (planetype != DRM_PLANE_TYPE_CURSOR) {
+                        msg_Dbg(vd, "plane id %d type %s pipe %c format %2d: %.4s",
+                                plane->plane_id, types[planetype],
+                                ('@'+ffs(plane->possible_crtcs)), i,
+                                (char*)&plane->formats[i]);
+                    }
+                }
+                drmModeFreePlane(plane);
+                drmModeFreeObjectProperties(props);
+            } else {
+                msg_Err(vd, "Couldn't get list of DRM formats");
+                drmModeFreePlaneResources(plane_res);
+                return false;
+            }
+        }
+        drmModeFreePlaneResources(plane_res);
+    }
+
+    if (sys->forced_drm_fourcc) {
+        for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
+            if (fourccmatching[c].drm == sys->drm_fourcc) {
+                sys->vlc_fourcc = fourccmatching[c].vlc;
+                break;
+            }
+        }
+        if (sys->plane_id == 0) {
+            msg_Err(vd, "Forced DRM fourcc (%.4s) not available in kernel.",
+                    (char*)&sys->drm_fourcc);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * favor yuv format according to YUVFormat flag.
+     * check for exact match first, then YUVFormat and then !YUVFormat
+     */
+    for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
+        if (fourccmatching[c].vlc == sys->vlc_fourcc) {
+            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",
+                        (char*)&sys->vlc_fourcc);
+                return false;
+            }
+            return true;
+        }
+    }
+
+    YUVFormat = vlc_fourcc_IsYUV(sys->vlc_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;
+                sys->plane_id = fourccmatching[c].plane_id;
+             }
+
+            sys->vlc_fourcc = fourccmatching[c].vlc;
+            return true;
+        }
+    }
+
+    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;
+                sys->plane_id = fourccmatching[c].plane_id;
+             }
+
+            sys->vlc_fourcc = fourccmatching[c].vlc;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static void CustomDestroyPicture(vout_display_t *vd)
+{
+    vout_window_t *wnd = vd->cfg->window;
+    for (int c = 0; c < MAXHWBUF; c++)
+        DestroyFB(vd, c);
+}
+
+static int OpenDisplay(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if (!ChromaNegotiation(vd))
+        return VLC_EGENERIC;
+
+    msg_Dbg(vd, "Using VLC chroma '%.4s', DRM chroma '%.4s'",
+            (char*)&sys->vlc_fourcc, (char*)&sys->drm_fourcc);
+    return VLC_SUCCESS;
+}
+
+
+static int Control(vout_display_t *vd, int query)
+{
+    (void) vd;
+
+    switch (query) {
+        case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
+        case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
+        case VOUT_DISPLAY_CHANGE_ZOOM:
+        case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
+        case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+            return VLC_SUCCESS;
+    }
+    return VLC_EGENERIC;
+}
+
+
+static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
+                    vlc_tick_t date)
+{
+    VLC_UNUSED(subpic); VLC_UNUSED(date);
+    vout_display_sys_t *sys = vd->sys;
+    picture_Copy( sys->picture, pic );
+}
+
+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;
+
+    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,
+            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]);
+        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];
+}
+
+/**
+ * Terminate an output method created by Open
+ */
+static void Close(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if (sys->picture)
+        picture_Release(sys->picture);
+    CustomDestroyPicture(vd);
+
+}
+
+static const struct vlc_display_operations ops = {
+    .close = Close,
+    .prepare = Prepare,
+    .display = Display,
+    .control = Control,
+};
+
+/**
+ * This function allocates and initializes a KMS vout method.
+ */
+static int Open(vout_display_t *vd,
+                video_format_t *fmtp, vlc_video_context *context)
+{
+    vout_display_sys_t *sys;
+    vlc_fourcc_t local_vlc_chroma;
+    uint32_t local_drm_chroma;
+    video_format_t fmt = {};
+    char *chroma;
+
+    if (vd->cfg->window->type != VOUT_WINDOW_TYPE_KMS)
+        return VLC_EGENERIC;
+
+    /*
+     * Allocate instance and initialize some members
+     */
+    vd->sys = sys = vlc_obj_calloc(VLC_OBJECT(vd), 1, sizeof(*sys));
+    if (!sys)
+        return VLC_ENOMEM;
+
+    chroma = var_InheritString(vd, "kms-vlc-chroma");
+    if (chroma) {
+        local_vlc_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma);
+
+        if (local_vlc_chroma) {
+            sys->vlc_fourcc = local_vlc_chroma;
+            msg_Dbg(vd, "Forcing VLC to use chroma '%4s'", chroma);
+         } else {
+            sys->vlc_fourcc = vd->source->i_chroma;
+            msg_Dbg(vd, "Chroma %4s invalid, using default", chroma);
+         }
+
+        free(chroma);
+        chroma = NULL;
+    } else {
+        sys->vlc_fourcc = vd->source->i_chroma;
+        msg_Dbg(vd, "Chroma not defined, using default");
+    }
+
+    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);
+
+        free(chroma);
+        chroma = NULL;
+    }
+
+    if (OpenDisplay(vd) != VLC_SUCCESS) {
+        Close(vd);
+        return VLC_EGENERIC;
+    }
+
+    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 = sys->vlc_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;
+    }
+
+    *fmtp = fmt;
+    vd->ops = &ops;
+
+    (void) context;
+    return VLC_SUCCESS;
+
+error:
+    return VLC_EGENERIC;
+}
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin ()
+    set_shortname("drm")
+    /* Keep kms here for compatibility with previous video output. */
+    add_shortcut("drm", "kms_drm", "kms")
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VOUT)
+
+    add_string( "kms-vlc-chroma", NULL, VLC_CHROMA_TEXT, VLC_CHROMA_LONGTEXT)
+    add_string( "kms-drm-chroma", NULL, DRM_CHROMA_TEXT, DRM_CHROMA_LONGTEXT)
+    set_description("Direct rendering management video output")
+    set_callback_display(Open, 30)
+vlc_module_end ()


=====================================
modules/video_output/kms.c
=====================================
@@ -2,6 +2,7 @@
  * kms.c : kernel mode setting plugin for vlc
  *****************************************************************************
  * Copyright © 2018 Intel Corporation
+ * Copyright © 2021 Videolabs
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -40,183 +41,83 @@
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_vout_display.h>
-#include <vlc_picture_pool.h>
 #include <vlc_fs.h>
+#include <vlc_vout_window.h>
+
+#include <assert.h>
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-#define KMS_VAR "kms"
+#define KMS_DEVICE_VAR "kms-device"
 
 #define DEVICE_TEXT "Framebuffer device"
 #define DEVICE_LONGTEXT \
-    "Framebuffer device to use for rendering (usually /dev/dri/card0)."
-
-#define VLC_CHROMA_TEXT "Image format used by VLC"
-#define VLC_CHROMA_LONGTEXT "Chroma fourcc request to VLC for output format"
-
-#define DRM_CHROMA_TEXT "Image format used by DRM"
-#define DRM_CHROMA_LONGTEXT "Chroma fourcc override for DRM framebuffer format selection"
+    "Framebuffer device to use for rendering (usually /dev/dri/card0 or /dev/drm0)."
 
-/*
- * how many hw buffers are allocated for page flipping. I think
- * 3 is enough so we shouldn't get unexpected stall from kernel.
- */
-#define   MAXHWBUF 3
+#define KMS_CONNECTOR_TEXT "DRM Connector"
+#define KMS_CONNECTOR_LONGTEXT \
+    "The DRM connector to use, using the naming conn-i where <conn> is the " \
+    "connector type name and <i> is the connector type id"
 
 typedef enum { drvSuccess, drvTryNext, drvFail } deviceRval;
 
-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;
-
-    unsigned int    front_buf;
-
-    bool            forced_drm_fourcc;
-    uint32_t        drm_fourcc;
-    vlc_fourcc_t    vlc_fourcc;
-
-/*
- * modeset information
- */
-    uint32_t        crtc;
-    uint32_t        plane_id;
-
-/*
- * other generic stuff
- */
-    int             drm_fd;
-} vout_display_sys_t;
-
-static void DestroyFB(vout_display_sys_t const *sys, uint32_t const buf)
-{
-    struct drm_mode_destroy_dumb destroy_req = { .handle = sys->handle[buf] };
-
-    munmap(sys->map[buf], sys->size);
-    drmModeRmFB(sys->drm_fd, sys->fb[buf]);
-    drmIoctl(sys->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
-}
-
-static deviceRval CreateFB(vout_display_t *vd, const int buf)
-{
-    vout_display_sys_t *sys = vd->sys;
-    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:
+static const char * const connector_type_names[] = {
+    [DRM_MODE_CONNECTOR_Unknown]      = "Unknown",
+    [DRM_MODE_CONNECTOR_VGA]          = "VGA",
+    [DRM_MODE_CONNECTOR_DVII]         = "DVI-I",
+    [DRM_MODE_CONNECTOR_DVID]         = "DVI-D",
+    [DRM_MODE_CONNECTOR_DVIA]         = "DVI-A",
+    [DRM_MODE_CONNECTOR_Composite]    = "Composite",
+    [DRM_MODE_CONNECTOR_SVIDEO]       = "SVIDEO",
+    [DRM_MODE_CONNECTOR_LVDS]         = "LVDS",
+    [DRM_MODE_CONNECTOR_Component]    = "Component",
+    [DRM_MODE_CONNECTOR_9PinDIN]      = "DIN",
+    [DRM_MODE_CONNECTOR_DisplayPort]  = "DP",
+    [DRM_MODE_CONNECTOR_HDMIA]        = "HDMI-A",
+    [DRM_MODE_CONNECTOR_HDMIB]        = "HDMI-B",
+    [DRM_MODE_CONNECTOR_TV]           = "TV",
+    [DRM_MODE_CONNECTOR_eDP]          = "eDP",
+    [DRM_MODE_CONNECTOR_VIRTUAL]      = "Virtual",
+    [DRM_MODE_CONNECTOR_DSI]          = "DSI",
+    [DRM_MODE_CONNECTOR_DPI]          = "DPI",
+    [DRM_MODE_CONNECTOR_WRITEBACK]    = "Writeback",
+#ifdef DRM_MODE_CONNECTOR_SPI
+    [DRM_MODE_CONNECTOR_SPI]          = "SPI",
 #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;
+#ifdef DRM_MODE_CONNECTOR_USB
+    [DRM_MODE_CONNECTOR_USB]          = "USB",
 #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(sys->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req);
-    if (ret < 0) {
-        msg_Err(vd, "Cannot create dumb buffer");
-        return drvFail;
-    }
+struct vout_window_sys_t {
+    /* modeset information */
+    uint32_t        crtc;
 
-    sys->size = create_req.size;
-    sys->handle[buf] = create_req.handle;
+    /* other generic stuff */
+    int             drm_fd;
 
     /*
-     * create framebuffer object for the dumb-buffer
-     * index 0 has to be filled in any case.
+     * buffer information
      */
-    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(sys->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(sys->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,
-                         sys->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(sys->drm_fd, sys->fb[buf]);
-    sys->fb[buf] = 0;
+    uint32_t        width;
+    uint32_t        height;
 
-err_destroy:
-    memset(&destroy_req, 0, sizeof(destroy_req));
-    destroy_req.handle = sys->handle[buf];
-    drmIoctl(sys->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_req);
-    return ret;
-}
+    drmModeRes *modeRes;
+    drmModeModeInfo *mode;
+    drmModeConnector *conn;
+    uint32_t connector;
+    drmModeCrtc *saved_crtc;
 
+    uint32_t framebuffer;
+    uint32_t main_buffer;
+};
 
-static deviceRval FindCRTC(vout_display_t *vd, drmModeRes const *res,
+static deviceRval FindCRTC(vout_window_t *wnd, drmModeRes const *res,
                              drmModeConnector const *conn)
 {
-    vout_display_sys_t *sys = vd->sys;
+    struct vout_window_sys_t *sys = wnd->sys;
     drmModeEncoder *enc;
     int i, j;
 
@@ -227,7 +128,7 @@ static deviceRval FindCRTC(vout_display_t *vd, drmModeRes const *res,
         enc = drmModeGetEncoder(sys->drm_fd, conn->encoder_id);
         if (enc) {
             if (enc->crtc_id) {
-                msg_Dbg(vd, "Got CRTC %d from current encoder", enc->crtc_id);
+                msg_Dbg(wnd, "Got CRTC %d from current encoder", enc->crtc_id);
 
                 sys->crtc = enc->crtc_id;
                 drmModeFreeEncoder(enc);
@@ -244,8 +145,7 @@ static deviceRval FindCRTC(vout_display_t *vd, drmModeRes const *res,
         enc = drmModeGetEncoder(sys->drm_fd, conn->encoders[i]);
 
         for (j = 0; enc && j < res->count_crtcs; ++j) {
-            if (ffs(enc->possible_crtcs) == j && res->crtcs[j]) {
-                msg_Dbg(vd, "Got CRTC %d", res->crtcs[j]);
+            if ((enc->possible_crtcs & (1 << j)) != 0 && res->crtcs[j]) {
                 sys->crtc = res->crtcs[j];
                 drmModeFreeEncoder(enc);
                 return drvSuccess;
@@ -254,499 +154,325 @@ static deviceRval FindCRTC(vout_display_t *vd, drmModeRes const *res,
         drmModeFreeEncoder(enc);
     }
 
-    msg_Err(vd , "Cannot find CRTC for connector %d", conn->connector_id);
+    msg_Err(wnd , "Cannot find CRTC for connector %d", conn->connector_id);
     return drvTryNext;
 }
 
 
-static deviceRval SetupDevice(vout_display_t *vd, drmModeRes const *res,
+static deviceRval SetupDevice(vout_window_t *wnd, drmModeRes const *res,
                              drmModeConnector const *conn)
 {
-    vout_display_sys_t *sys = vd->sys;
+    struct vout_window_sys_t *sys = wnd->sys;
     deviceRval ret;
-    int c, c2;
 
     if (conn->connection != DRM_MODE_CONNECTED || conn->count_modes == 0)
         return drvTryNext;
 
     sys->width = conn->modes[0].hdisplay;
     sys->height = conn->modes[0].vdisplay;
-    msg_Dbg(vd, "Mode resolution for connector %u is %ux%u",
+    sys->mode = &conn->modes[0];
+    msg_Dbg(wnd, "Mode resolution for connector %u is %ux%u",
             conn->connector_id, sys->width, sys->height);
 
-    ret = FindCRTC(vd, res, conn);
+    ret = FindCRTC(wnd, res, conn);
     if (ret != drvSuccess) {
-        msg_Dbg(vd , "No valid CRTC for connector %d", conn->connector_id);
+        msg_Dbg(wnd, "No valid CRTC for connector %d", conn->connector_id);
         return ret;
     }
-
-    for (c = 0; c < MAXHWBUF; c++) {
-        ret = CreateFB(vd, c);
-        if (ret != drvSuccess) {
-            msg_Err(vd, "Cannot create framebuffer %d for connector %d", c,
-                    conn->connector_id);
-            for (c2 = 0; c2 < c; c2++)
-                DestroyFB(sys, c2);
-
-            return ret;
-        } else {
-            msg_Dbg(vd, "Created HW framebuffer %d/%d", c+1, MAXHWBUF);
-        }
-    }
     return drvSuccess;
 }
 
-
-/** 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::vlc VLC fourcc code from vlc_fourcc.h under title 'Chromas'
- * 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
+static void UpdateOutputs(vout_window_t *wnd)
 {
-    uint32_t     drm;
-    vlc_fourcc_t vlc;
-    uint32_t     plane_id;
-    bool         present;
-    bool         isYUV;
-} fourccmatching[] = {
-    { .drm = DRM_FORMAT_XRGB8888, .vlc = VLC_CODEC_RGB32, .isYUV = false },
-    { .drm = DRM_FORMAT_RGB565, .vlc = VLC_CODEC_RGB16, .isYUV = false },
-#if defined DRM_FORMAT_P010
-    { .drm = DRM_FORMAT_P010, .vlc = VLC_CODEC_P010, .isYUV = true },
-#endif
-    { .drm = DRM_FORMAT_NV12, .vlc = VLC_CODEC_NV12, .isYUV = true },
-    { .drm = DRM_FORMAT_YUYV, .vlc = VLC_CODEC_YUYV, .isYUV = true },
-    { .drm = DRM_FORMAT_YVYU, .vlc = VLC_CODEC_YVYU, .isYUV = true },
-    { .drm = DRM_FORMAT_UYVY, .vlc = VLC_CODEC_UYVY, .isYUV = true },
-    { .drm = DRM_FORMAT_VYUY, .vlc = VLC_CODEC_VYUY, .isYUV = true },
-};
-
+    struct vout_window_sys_t *sys = wnd->sys;
+    drmModeRes *modeRes = sys->modeRes;
 
-static void CheckFourCCList(uint32_t drmfourcc, uint32_t plane_id)
-{
-    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;
+    msg_Info(wnd, "Updating list of connectors:");
+    for (int c = 0; c < modeRes->count_connectors && sys->crtc == 0; c++)
+    {
+        drmModeConnector *conn =
+            drmModeGetConnector(sys->drm_fd, modeRes->connectors[c]);
+        if (conn == NULL)
+            continue;
 
-            fourccmatching[i].present = true;
-            fourccmatching[i].plane_id = plane_id;
-            break;
+        if (conn->connector_type >= ARRAY_SIZE(connector_type_names) ||
+            conn->connection != DRM_MODE_CONNECTED)
+        {
+            drmModeFreeConnector(conn);
+            continue;
         }
-    }
-}
 
+        char name[32];
+        snprintf(name, sizeof name, "%s-%d",
+                 connector_type_names[conn->connector_type],
+                 conn->connector_type_id);
 
-static bool ChromaNegotiation(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-    unsigned i, c, propi;
-    uint32_t planetype;
-    const char types[][16] = { "OVERLAY", "PRIMARY", "CURSOR", "UNKNOWN" };
-    drmModePlaneRes *plane_res = NULL;
-    drmModePlane *plane;
-    drmModeObjectProperties *props;
-    drmModePropertyPtr pp;
-    bool YUVFormat;
+        /* Iterate all available encoders to find CRTC */
+        for (int i = 0; i < conn->count_encoders; i++)
+        {
+            drmModeEncoder *enc =
+                drmModeGetEncoder(sys->drm_fd, conn->encoders[i]);
 
-    /*
-     * For convenience print out in debug prints all supported
-     * DRM modes so they can be seen if use verbose mode.
-     */
-    plane_res = drmModeGetPlaneResources(sys->drm_fd);
-    sys->plane_id = 0;
-
-    if (plane_res != NULL && plane_res->count_planes > 0) {
-        msg_Dbg(vd, "List of DRM supported modes on this machine:");
-        for (c = 0; c < plane_res->count_planes; c++) {
-
-            plane = drmModeGetPlane(sys->drm_fd, plane_res->planes[c]);
-            if (plane != NULL && plane->count_formats > 0) {
-                props = drmModeObjectGetProperties(sys->drm_fd,
-                                                   plane->plane_id,
-                                                   DRM_MODE_OBJECT_PLANE);
-
-                planetype = 3;
-                pp = NULL;
-                for (propi = 0; propi < props->count_props; propi++) {
-                    pp = drmModeGetProperty(sys->drm_fd, props->props[propi]);
-                    if (strcmp(pp->name, "type") == 0) {
-                        break;
-                    }
-                    drmModeFreeProperty(pp);
-                }
-
-                if (pp != NULL) {
-                    drmModeFreeProperty(pp);
-                    planetype = props->prop_values[propi];
-                }
-
-                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;
-                    }
-
-                    /*
-                     * we don't advertise about cursor plane because
-                     * of its special limitations.
-                     */
-                    if (planetype != DRM_PLANE_TYPE_CURSOR) {
-                        msg_Dbg(vd, "plane id %d type %s pipe %c format %2d: %.4s",
-                                plane->plane_id, types[planetype],
-                                ('@'+ffs(plane->possible_crtcs)), i,
-                                (char*)&plane->formats[i]);
-                    }
-                }
-                drmModeFreePlane(plane);
-            } else {
-                msg_Err(vd, "Couldn't get list of DRM formats");
-                drmModeFreePlaneResources(plane_res);
-                return false;
-            }
-        }
-        drmModeFreePlaneResources(plane_res);
-    }
+            size_t crtc_index = sys->crtc;
+            if ((enc->possible_crtcs & (1 << crtc_index)) != 0) {
 
-    if (sys->forced_drm_fourcc) {
-        for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-            if (fourccmatching[c].drm == sys->drm_fourcc) {
-                sys->vlc_fourcc = fourccmatching[c].vlc;
+                drmModeFreeEncoder(enc);
+                vout_window_ReportOutputDevice(wnd, name, name);
                 break;
             }
+            drmModeFreeEncoder(enc);
         }
-        if (sys->plane_id == 0) {
-            msg_Err(vd, "Forced DRM fourcc (%.4s) not available in kernel.",
-                    (char*)&sys->drm_fourcc);
-            return false;
-        }
-        return true;
-    }
-
-    /*
-     * favor yuv format according to YUVFormat flag.
-     * check for exact match first, then YUVFormat and then !YUVFormat
-     */
-    for (c = i = 0; c < ARRAY_SIZE(fourccmatching); c++) {
-        if (fourccmatching[c].vlc == sys->vlc_fourcc) {
-            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",
-                        (char*)&sys->vlc_fourcc);
-                return false;
-            }
-            return true;
-        }
-    }
-
-    YUVFormat = vlc_fourcc_IsYUV(sys->vlc_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;
-                sys->plane_id = fourccmatching[c].plane_id;
-             }
-
-            sys->vlc_fourcc = fourccmatching[c].vlc;
-            return true;
-        }
-    }
-
-    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;
-                sys->plane_id = fourccmatching[c].plane_id;
-             }
-
-            sys->vlc_fourcc = fourccmatching[c].vlc;
-            return true;
-        }
+        drmModeFreeConnector(conn);
     }
-
-    return false;
 }
 
-static void CustomDestroyPicture(vout_display_sys_t *sys)
+static int WindowEnable(vout_window_t *wnd, const vout_window_cfg_t *cfg)
 {
-    int c;
-
-    for (c = 0; c < MAXHWBUF; c++)
-        DestroyFB(sys, c);
-
-    drmSetClientCap(sys->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
-    drmDropMaster(sys->drm_fd);
-    vlc_close(sys->drm_fd);
-    sys->drm_fd = 0;
-}
+    struct vout_window_sys_t *sys = wnd->sys;
+    (void)cfg;
+    drmModeRes *modeRes = sys->modeRes;
 
-static int OpenDisplay(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
-    char *psz_device;
-    int ret;
-    uint64_t dumbRet;
-    drmModeConnector *conn;
-    drmModeRes *modeRes;
-    int c;
     bool found_connector = false;
 
-    /*
-     * Open framebuffer device
-     */
-    psz_device = var_InheritString(vd, KMS_VAR);
-    if (psz_device == NULL) {
-        msg_Err(vd, "Don't know which DRM device to open");
-        return VLC_EGENERIC;
-    }
-
-    sys->drm_fd = vlc_open(psz_device, O_RDWR);
-    if (sys->drm_fd == -1) {
-        msg_Err(vd, "cannot open %s", psz_device);
-        free(psz_device);
-        return VLC_EGENERIC;
-    }
-
-    drmSetClientCap(sys->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
-
-    if (!ChromaNegotiation(vd))
-    {
-        free(psz_device);
-        goto err_out;
-    }
-
-    msg_Dbg(vd, "Using VLC chroma '%.4s', DRM chroma '%.4s'",
-            (char*)&sys->vlc_fourcc, (char*)&sys->drm_fourcc);
+    // TODO: use kms-connector as a list of connector for clones
+    char *connector_request = var_InheritString(wnd, "kms-connector");
+    msg_Info(wnd, "Looping over %d resources", modeRes->count_connectors);
+    for (int c = 0; c < modeRes->count_connectors && sys->crtc == 0; c++) {
 
-    ret = drmGetCap(sys->drm_fd, DRM_CAP_DUMB_BUFFER, &dumbRet);
-    if (ret < 0 || !dumbRet) {
-        msg_Err(vd, "Device '%s' does not support dumb buffers", psz_device);
-        free(psz_device);
-        goto err_out;
-    }
-    free(psz_device);
+        drmModeConnector *conn =
+            drmModeGetConnector(sys->drm_fd, modeRes->connectors[c]);
+        if (conn == NULL)
+            continue;
 
-    modeRes = drmModeGetResources(sys->drm_fd);
-    if (modeRes == NULL) {
-        msg_Err(vd, "Didn't get DRM resources");
-        goto err_out;
-    }
+        if (conn->connector_type >= ARRAY_SIZE(connector_type_names))
+        {
+            drmModeFreeConnector(conn);
+            continue;
+        }
 
-    for (c = 0; c < modeRes->count_connectors && sys->crtc == 0; c++) {
+        char name[32];
+        snprintf(name, sizeof name, "%s-%d",
+                 connector_type_names[conn->connector_type],
+                 conn->connector_type_id);
 
-        conn = drmModeGetConnector(sys->drm_fd, modeRes->connectors[c]);
-        if (conn == NULL)
+        if (connector_request != NULL && strcmp(name, connector_request) != 0)
+        {
+            msg_Info(wnd, "connector %s skipped", name);
+            drmModeFreeConnector(conn);
             continue;
+        }
+
+        msg_Info(wnd, "connector %d: %s", c, name);
 
         found_connector = true;
 
-        ret = SetupDevice(vd, modeRes, conn);
+        int ret = SetupDevice(wnd, modeRes, conn);
         if (ret != drvSuccess) {
             if (ret != drvTryNext) {
-                msg_Err(vd, "Cannot do setup for connector %u:%u", c,
-                        modeRes->connectors[c]);
+                msg_Err(wnd, "Cannot do setup for connector %s %u:%u",
+                        name, c, modeRes->connectors[c]);
 
                 drmModeFreeConnector(conn);
                 drmModeFreeResources(modeRes);
-                goto err_out;
+                free(connector_request);
+                return VLC_EGENERIC;
             }
             drmModeFreeConnector(conn);
             found_connector = false;
+            msg_Dbg(wnd, " - Connector %d: could not setup device", c);
             continue;
         }
-        drmModeFreeConnector(conn);
+        sys->connector = conn->connector_id;
+        sys->conn = conn;
+        break;
     }
-    drmModeFreeResources(modeRes);
+    free(connector_request);
 
     if (!found_connector)
-        goto err_out;
+    {
+        msg_Warn(wnd, "Could not find a valid connector");
+        return VLC_EGENERIC;
+    }
+
+    wnd->handle.crtc = sys->crtc;
+    /* Store current KMS state before modifying */
+    sys->saved_crtc = drmModeGetCrtc(sys->drm_fd, sys->crtc);
 
-    picture_resource_t rsc = { 0 };
+    /*
+     * Create a new framebuffer to avoid compositing the planes into the saved
+     * framebuffer for the current CRTC.
+     */
 
-    sys->picture = picture_NewFromResource(vd->source, &rsc);
+    struct drm_mode_create_dumb request = {
+        .width = sys->width, .height = sys->height, .bpp = 32
+    };
 
-    if (!sys->picture)
-        goto err_out;
+    int ret = drmIoctl(sys->drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &request);
+    if (ret != drvSuccess)
+        goto error_create_dumb;
 
-    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;
-    }
+    uint32_t new_fb;
+    ret = drmModeAddFB(sys->drm_fd, sys->width, sys->height, 24, 32, request.pitch,
+            request.handle, &new_fb);
+    if (ret != drvSuccess)
+        goto error_add_fb;
+
+    ret = drmModeSetCrtc(sys->drm_fd, sys->crtc, new_fb, 0, 0, &sys->connector, 1, sys->mode);
+    if (ret != drvSuccess)
+        goto error_set_crtc;
+
+    sys->framebuffer = new_fb;
+    sys->main_buffer = request.handle;
+
+    vout_window_ReportSize(wnd, sys->width, sys->height);
 
     return VLC_SUCCESS;
-err_out:
-    drmDropMaster(sys->drm_fd);
-    vlc_close(sys->drm_fd);
-    sys->drm_fd = 0;
-    return VLC_EGENERIC;
-}
 
+error_set_crtc:
+    drmModeRmFB(sys->drm_fd, new_fb);
+
+error_add_fb:
+    struct drm_mode_destroy_dumb destroy_request = {
+        .handle = request.handle
+    };
+    ret = drmIoctl(sys->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+    /* This must be a programmation error if we cannot destroy the resources
+     * we created. */
+    assert(ret == drvSuccess);
+
+error_create_dumb:
+    if (sys->saved_crtc != NULL)
+        drmModeFreeCrtc(sys->saved_crtc);
+    sys->saved_crtc = NULL;
+    drmModeFreeConnector(sys->conn);
+    sys->conn = NULL;
 
-static int Control(vout_display_t *vd, int query)
-{
-    (void) vd;
-
-    switch (query) {
-        case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
-        case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
-        case VOUT_DISPLAY_CHANGE_ZOOM:
-        case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
-        case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
-            return VLC_SUCCESS;
-    }
     return VLC_EGENERIC;
 }
 
-
-static void Prepare(vout_display_t *vd, picture_t *pic, subpicture_t *subpic,
-                    vlc_tick_t date)
+static void WindowDisable(vout_window_t *wnd)
 {
-    VLC_UNUSED(subpic); VLC_UNUSED(date);
-    vout_display_sys_t *sys = vd->sys;
-    picture_Copy( sys->picture, pic );
-}
-
+    struct vout_window_sys_t *sys = wnd->sys;
+    sys->crtc = 0;
 
-static void Display(vout_display_t *vd, picture_t *picture)
-{
-    VLC_UNUSED(picture);
-    vout_display_sys_t *sys = vd->sys;
-    int i;
-
-    if (drmModeSetPlane(sys->drm_fd, sys->plane_id, sys->crtc,
-                         sys->fb[sys->front_buf], 0,
-                         0, 0, sys->width, sys->height,
-                         0, 0, sys->width << 16, sys->height << 16)) {
-        msg_Err(vd, "Cannot do set plane for plane id %u, fb %x",
-                sys->plane_id,
-                sys->fb[sys->front_buf]);
-    } else {
-        sys->front_buf++;
-        sys->front_buf %= MAXHWBUF;
-
-        for (i = 0; i < PICTURE_PLANE_MAX; i++)
-            sys->picture->p[i].p_pixels =
-                    sys->map[sys->front_buf]+sys->offsets[i];
+    /* Restore previous CRTC state */
+    if (sys->saved_crtc)
+    {
+        int ret = drmModeSetCrtc(sys->drm_fd,
+            sys->saved_crtc->crtc_id,
+            sys->saved_crtc->buffer_id,
+            sys->saved_crtc->x, sys->saved_crtc->y,
+            &sys->connector, 1,
+            &sys->saved_crtc->mode);
+        assert(ret == drvSuccess);
+        drmModeFreeCrtc(sys->saved_crtc);
     }
-}
+    sys->saved_crtc = NULL;
 
+    drmModeFreeConnector(sys->conn);
 
-/**
- * Terminate an output method created by Open
- */
-static void Close(vout_display_t *vd)
-{
-    vout_display_sys_t *sys = vd->sys;
+    drmModeRmFB(sys->drm_fd, sys->framebuffer);
 
-    if (sys->picture)
-        picture_Release(sys->picture);
-    CustomDestroyPicture(sys);
+    struct drm_mode_destroy_dumb destroy_request = {
+        .handle = sys->main_buffer,
+    };
+    int ret = drmIoctl(sys->drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
+    /* This must be a programmation error if we cannot destroy the resources
+     * we created. */
+    assert(ret == drvSuccess);
+    (void)ret;
+}
 
-    if (sys->drm_fd)
-        drmDropMaster(sys->drm_fd);
+static void WindowClose(vout_window_t *wnd)
+{
+    struct vout_window_sys_t *sys = wnd->sys;
+    drmModeFreeResources(sys->modeRes);
+    drmSetClientCap(sys->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+    drmDropMaster(sys->drm_fd);
+    vlc_close(sys->drm_fd);
+    free(sys);
 }
 
-static const struct vlc_display_operations ops = {
-    .close = Close,
-    .prepare = Prepare,
-    .display = Display,
-    .control = Control,
+static const struct vout_window_operations window_ops =
+{
+    .destroy = WindowClose,
+    .enable = WindowEnable,
+    .disable = WindowDisable,
 };
 
-/**
- * This function allocates and initializes a KMS vout method.
- */
-static int Open(vout_display_t *vd,
-                video_format_t *fmtp, vlc_video_context *context)
+static int OpenWindow(vout_window_t *wnd)
 {
-    vout_display_sys_t *sys;
-    vlc_fourcc_t local_vlc_chroma;
-    uint32_t local_drm_chroma;
-    video_format_t fmt = {};
-    char *chroma;
+    char *psz_device;
 
-    if (vout_display_cfg_IsWindowed(vd->cfg))
-        return VLC_EGENERIC;
+
+    struct vout_window_sys_t *sys
+        = wnd->sys
+        = malloc(sizeof *sys);
+    if (sys == NULL)
+        return VLC_ENOMEM;
+
+    sys->crtc = 0;
 
     /*
-     * Allocate instance and initialize some members
+     * Open framebuffer device
      */
-    vd->sys = sys = vlc_obj_calloc(VLC_OBJECT(vd), 1, sizeof(*sys));
-    if (!sys)
-        return VLC_ENOMEM;
+    psz_device = var_InheritString(wnd, KMS_DEVICE_VAR);
+    if (psz_device == NULL) {
+        msg_Err(wnd, "Don't know which DRM device to open");
+        goto error_end;
+    }
 
-    chroma = var_InheritString(vd, "kms-vlc-chroma");
-    if (chroma) {
-        local_vlc_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma);
-
-        if (local_vlc_chroma) {
-            sys->vlc_fourcc = local_vlc_chroma;
-            msg_Dbg(vd, "Forcing VLC to use chroma '%4s'", chroma);
-         } else {
-            sys->vlc_fourcc = vd->source->i_chroma;
-            msg_Dbg(vd, "Chroma %4s invalid, using default", chroma);
-         }
-
-        free(chroma);
-        chroma = NULL;
-    } else {
-        sys->vlc_fourcc = vd->source->i_chroma;
-        msg_Dbg(vd, "Chroma not defined, using default");
+    sys->drm_fd = vlc_open(psz_device, O_RDWR);
+    if (sys->drm_fd == -1) {
+        msg_Err(wnd, "cannot open %s", psz_device);
+        free(psz_device);
+        goto error_end;
     }
 
-    chroma = var_InheritString(vd, "kms-drm-chroma");
-    if (chroma) {
-        local_drm_chroma = VLC_FOURCC(chroma[0], chroma[1], chroma[2],
-                                      chroma[3]);
+    drmVersionPtr version;
+    if ((version = drmGetVersion(sys->drm_fd)) != NULL)
+    {
+        const char *date = version->date ? version->date : "unknown";
+        const char *desc = version->desc ? version->desc : "unknown";
 
-        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);
+        msg_Dbg(wnd, "Using DRM driver %s version %d.%d.%d (build %s): %s",
+                version->name, version->version_major, version->version_minor,
+                version->version_patchlevel, date, desc);
 
-        free(chroma);
-        chroma = NULL;
+        drmFreeVersion(version);
     }
-
-    if (OpenDisplay(vd) != VLC_SUCCESS) {
-        Close(vd);
-        return VLC_EGENERIC;
+    else
+    {
+        msg_Err(wnd, "device %s doesn't support DRM", psz_device);
+        free(psz_device);
+        goto error_drm;
     }
+    free(psz_device);
+
+    drmSetClientCap(sys->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
 
-    video_format_ApplyRotation(&fmt, vd->source);
+    sys->modeRes = drmModeGetResources(sys->drm_fd);
+    if (sys->modeRes == NULL) {
+        msg_Err(wnd, "Didn't get DRM resources");
+        drmSetClientCap(sys->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
+        goto error_drm;
+    }
 
-    fmt.i_width = fmt.i_visible_width  = sys->width;
-    fmt.i_height = fmt.i_visible_height = sys->height;
-    fmt.i_chroma = sys->vlc_fourcc;
-    *fmtp = fmt;
+    wnd->ops = &window_ops;
+    wnd->type = VOUT_WINDOW_TYPE_KMS;
+    wnd->display.drm_fd = sys->drm_fd;
+    /* Note: wnd->handle.crtc will be initialized later */
 
-    vd->ops = &ops;
+    UpdateOutputs(wnd);
 
-    (void) context;
     return VLC_SUCCESS;
+error_drm:
+    drmDropMaster(sys->drm_fd);
+    vlc_close(sys->drm_fd);
+
+error_end:
+    free(sys);
+    return VLC_EGENERIC;
 }
 
 
@@ -756,10 +482,14 @@ static int Open(vout_display_t *vd,
 vlc_module_begin ()
     set_shortname("kms")
     set_subcategory(SUBCAT_VIDEO_VOUT)
-    add_loadfile(KMS_VAR, "/dev/dri/card0", DEVICE_TEXT, DEVICE_LONGTEXT)
 
-    add_string( "kms-vlc-chroma", NULL, VLC_CHROMA_TEXT, VLC_CHROMA_LONGTEXT)
-    add_string( "kms-drm-chroma", NULL, DRM_CHROMA_TEXT, DRM_CHROMA_LONGTEXT)
-    set_description("Linux kernel mode setting video output")
-    set_callback_display(Open, 30)
+    add_obsolete_string("kms") /* Since 4.0.0 */
+    add_loadfile(KMS_DEVICE_VAR, DRM_DIR_NAME "/" DRM_PRIMARY_MINOR_NAME "0",
+                 DEVICE_TEXT, DEVICE_LONGTEXT)
+    add_string("kms-connector", "", KMS_CONNECTOR_TEXT, KMS_CONNECTOR_LONGTEXT)
+
+    set_description("Linux kernel mode setting window provider")
+    set_callback(OpenWindow)
+    set_capability("vout window", 10)
+
 vlc_module_end ()


=====================================
modules/video_output/opengl/Makefile.am
=====================================
@@ -165,6 +165,10 @@ endif
 libegl_display_gbm_plugin_la_SOURCES = video_output/opengl/egl_display_gbm.c
 libegl_display_gbm_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(EGL_FLAGS) $(GBM_CFLAGS)
 libegl_display_gbm_plugin_la_LIBADD = $(EGL_LIBS) $(GBM_LIBS)
+if HAVE_KMS
+# DRM headers are bringing defines useful for opening DRM devices
+libegl_display_gbm_plugin_la_CPPFLAGS += $(KMS_CFLAGS) -DHAVE_KMS=1
+endif
 if HAVE_EGL
 if HAVE_GBM
 vout_LTLIBRARIES += libegl_display_gbm_plugin.la


=====================================
modules/video_output/opengl/egl_display_gbm.c
=====================================
@@ -31,8 +31,13 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+
 #include <gbm.h>
 
+#ifdef HAVE_KMS
+#include <xf86drm.h>
+#endif
+
 #include "egl_display.h"
 
 struct sys
@@ -57,11 +62,17 @@ static void Close(struct vlc_egl_display *display)
 static int
 OpenDeviceFd(const char **out_path)
 {
+/* DRM_DIR_NAME should be defined in xf86drm.h. */
+#ifndef DRM_DIR_NAME
+# define DRM_DIR_NAME "/dev/dri"
+#endif
+
+    /* Usually, /dev/dri/renderD* or /dev/dri/card* on Linux */
     static const char *default_drm_device_paths[] = {
-        "/dev/dri/renderD128",
-        "/dev/dri/card0",
-        "/dev/dri/renderD129",
-        "/dev/dri/card1",
+        DRM_DIR_NAME "/" DRM_RENDER_MINOR_NAME "128",
+        DRM_DIR_NAME "/" DRM_PRIMARY_MINOR_NAME "0",
+        DRM_DIR_NAME "/" DRM_RENDER_MINOR_NAME "129",
+        DRM_DIR_NAME "/" DRM_PRIMARY_MINOR_NAME "1",
     };
 
     for (size_t i = 0; i < ARRAY_SIZE(default_drm_device_paths); ++i)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/61314e523c599a968eddea515fcab32a74bd0a51...2a491074fb2a6176d73cca9ec0cbce32bb34a62c

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




More information about the vlc-commits mailing list