From fbf11a41e135c2b380ce51c9c90278dbcfc60c3d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 6 Nov 2020 11:14:49 +0100 Subject: [PATCH] backend/session: wait for DRM device if none found Wait for a DRM device if none is found in wlr_session_find_gpus. This can happen if the compositor is loaded before the display kernel driver. This supersedes the logind CanGraphical property. To test, e.g. with i915 and sway: rmmod -f i915 sway & modprobe i915 Closes: https://github.com/swaywm/wlroots/issues/2093 --- backend/session/session.c | 65 ++++++++++++++++++++++++++++++++--- include/wlr/backend/session.h | 1 + 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/backend/session/session.c b/backend/session/session.c index a94793c8..c7808212 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -170,6 +170,8 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { goto error_mon; } + session->display = disp; + session->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(disp, &session->display_destroy); @@ -301,6 +303,36 @@ static size_t explicit_find_gpus(struct wlr_session *session, return i; } +static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { + struct udev_enumerate *en = udev_enumerate_new(udev); + if (!en) { + wlr_log(WLR_ERROR, "udev_enumerate_new failed"); + return NULL; + } + + udev_enumerate_add_match_subsystem(en, "drm"); + udev_enumerate_add_match_sysname(en, "card[0-9]*"); + + if (udev_enumerate_scan_devices(en) != 0) { + wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed"); + udev_enumerate_unref(en); + return NULL; + } + + return en; +} + +struct find_gpus_add_handler { + bool added; + struct wl_listener listener; +}; + +static void find_gpus_handle_add(struct wl_listener *listener, void *data) { + struct find_gpus_add_handler *handler = + wl_container_of(listener, handler, listener); + handler->added = true; +} + /* Tries to find the primary GPU by checking for the "boot_vga" attribute. * If it's not found, it returns the first valid GPU it finds. */ @@ -311,15 +343,38 @@ size_t wlr_session_find_gpus(struct wlr_session *session, return explicit_find_gpus(session, ret_len, ret, explicit); } - struct udev_enumerate *en = udev_enumerate_new(session->udev); + struct udev_enumerate *en = enumerate_drm_cards(session->udev); if (!en) { - wlr_log(WLR_ERROR, "Failed to create udev enumeration"); return -1; } - udev_enumerate_add_match_subsystem(en, "drm"); - udev_enumerate_add_match_sysname(en, "card[0-9]*"); - udev_enumerate_scan_devices(en); + if (udev_enumerate_get_list_entry(en) == NULL) { + udev_enumerate_unref(en); + wlr_log(WLR_INFO, "Waiting for a DRM card device"); + + struct find_gpus_add_handler handler = {0}; + handler.listener.notify = find_gpus_handle_add; + wl_signal_add(&session->events.add_drm_card, &handler.listener); + + struct wl_event_loop *event_loop = + wl_display_get_event_loop(session->display); + while (!handler.added) { + int ret = wl_event_loop_dispatch(event_loop, -1); + if (ret < 0) { + wlr_log_errno(WLR_ERROR, "Failed to wait for DRM card device: " + "wl_event_loop_dispatch failed"); + udev_enumerate_unref(en); + return -1; + } + } + + wl_list_remove(&handler.listener.link); + + en = enumerate_drm_cards(session->udev); + if (!en) { + return -1; + } + } struct udev_list_entry *entry; size_t i = 0; diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index b63c356c..692d7be1 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -40,6 +40,7 @@ struct wlr_session { struct wl_list devices; + struct wl_display *display; struct wl_listener display_destroy; struct {