diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 39824f55c6..17609bdb93 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -12,9 +12,9 @@ #include #include #include -#include #include "backend/drm/drm.h" #include "util/signal.h" +#include struct wlr_drm_backend *get_drm_backend_from_backend( struct wlr_backend *wlr_backend) { @@ -28,23 +28,26 @@ static bool backend_start(struct wlr_backend *backend) { return true; } -static void print_trace(void) -{ - void *array[10]; - char **strings; - int size, i; +static int bt_callback(void *data, uintptr_t pc, + const char *filename, int lineno, + const char *function) { + wlr_log(WLR_DEBUG, "Backtrace: %s in %s:%d", function, filename, lineno); + return 0; +} - size = backtrace (array, 10); - strings = backtrace_symbols (array, size); - if (strings != NULL) - { +static void bt_error(void *data, const char *msg, + int errnum) { + wlr_log(WLR_ERROR, "Backtrace error%s", msg); +} - fprintf (stderr, "Obtained %d stack frames.\n", size); - for (i = 0; i < size; i++) - fprintf (stderr, "%s\n", strings[i]); - } +static void print_trace(void) { + wlr_log(WLR_DEBUG, "Trying to obtain a backtrace"); + + struct backtrace_state *s = backtrace_create_state(NULL, 0,bt_error, NULL); + + wlr_log(WLR_DEBUG, "Tried to obtain a backtrace"); - free (strings); + backtrace_full(s, 0, bt_callback, bt_error, NULL); } static void backend_destroy(struct wlr_backend *backend) { @@ -134,20 +137,49 @@ static void drm_invalidated(struct wl_listener *listener, void *data) { char *name = drmGetDeviceNameFromFd2(drm->fd); wlr_log(WLR_DEBUG, "%s invalidated", name); - wlr_log(WLR_INFO, "Should we destroy the DRM backend? %s", name); - if(drm->parent != NULL) { - char *name2 = drmGetDeviceNameFromFd2(drm->parent->fd); - wlr_log(WLR_INFO, "Parent drm backend: %p %s", drm->parent, name2); - free(name2); + + + size_t seen_len = wl_list_length(&drm->outputs); + wlr_log(WLR_DEBUG, "%ld outputs before scan", seen_len); + + scan_drm_connectors(drm); + + // if all the drm connectors (outputs?) are disconnected, then we try to + // destroy the whole drm backend so we can unload drivers etc... + struct wlr_drm_connector *c = NULL; + bool all_disconnected = true; + wl_list_for_each(c, &drm->outputs, link) { + if(c->state != WLR_DRM_CONN_DISCONNECTED) { + all_disconnected = false; + } + wlr_log(WLR_INFO, "drm connector state: %s", c->output.name); + wlr_log(WLR_INFO, "drm connector state: %d", c->state); + wlr_log(WLR_INFO, "drm connector output mode: %p", c->desired_mode); + wlr_log(WLR_INFO, "drm connector output mode: %d", c->output.enabled); } - wlr_log(WLR_INFO, "Trying to anyway... hehe"); - // wlr_backend_destroy(conn->output.backend); + seen_len = wl_list_length(&drm->outputs); + wlr_log(WLR_DEBUG, "%ld outputs after scan", seen_len); + + // TODO: only destroy backend if we find that all drm_connectors have been lost ? + // i.e.: have unplugged all monitors + + wlr_log(WLR_INFO, "Should we destroy the DRM backend? %s - %d", name, all_disconnected); free(name); - scan_drm_connectors(drm); + if(drm->parent != NULL) { + name = drmGetDeviceNameFromFd2(drm->parent->fd); + wlr_log(WLR_INFO, "Parent drm backend: %p %s", drm->parent, name); + free(name); + } - wlr_backend_destroy(&drm->backend); + print_trace(); + + if(all_disconnected) { + wlr_log(WLR_INFO, "Destroying DRM backend anyway... hehe"); + // this is what we added - to destroy the backend when drm is invalidated... + wlr_backend_destroy(&drm->backend); + } } static void handle_session_destroy(struct wl_listener *listener, void *data) { diff --git a/backend/session/session.c b/backend/session/session.c index d8e9509d8d..c12e4f1a61 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "backend/session/session.h" #include "util/signal.h" @@ -32,6 +33,28 @@ static const struct session_impl *impls[] = { NULL, }; +// determines if the sysname is of the form card[0-9]* +static bool is_card(const char *name) { + wlr_log(WLR_DEBUG, "determining if '%s' is a card", name); + + if(strncmp(name, "card", strlen("card")) != 0) { + // doesn't start with card + return false; + } + + name = name + strlen("card"); + while(*name != '\0') { + if(!isdigit(*name)) { + return false; + } + name++; + } + + return true; +} + +// NOTE to self: this is an important function - need to look at this to detect e.g.: +// when new graphics cards / drm devices are added to the system static int udev_event(int fd, uint32_t mask, void *data) { struct wlr_session *session = data; @@ -45,17 +68,54 @@ static int udev_event(int fd, uint32_t mask, void *data) { wlr_log(WLR_DEBUG, "udev event for %s (%s)", udev_device_get_sysname(udev_dev), action); - if (!action || strcmp(action, "change") != 0) { + if (!action) { goto out; } dev_t devnum = udev_device_get_devnum(udev_dev); struct wlr_device *dev; + bool found = false; wl_list_for_each(dev, &session->devices, link) { if (dev->dev == devnum) { - wlr_signal_emit_safe(&dev->signal, session); - break; + found = true; + if (strcmp(action, "change") == 0) { + wlr_log(WLR_DEBUG, "found device for event %ld", dev->dev); + wlr_signal_emit_safe(&dev->signal, session); + break; + } + } + } + + // there is a drm device which we don't yet know about + // in the `wlr_session_find_gpus` function, they use + // - udev_enumerate_add_match_subsystem(en, "drm") + // - udev_enumerate_add_match_sysname(en, "card[0-9]*") + // + // to restrict to only GPUs + // we attempt to do the same with `udev_device_get_subsystem` + // and `udev_device_get_sysname` + if (!found && strcmp(action, "add") == 0 + && strcmp(udev_device_get_subsystem(udev_dev), "drm") == 0 + && is_card(udev_device_get_sysname(udev_dev))) { + wlr_log(WLR_INFO, "wlroots detected a fresh drm device, trying to add to backend"); + + int gpu_fd = session_try_add_gpu(session, udev_dev); + + if(gpu_fd >= 0) { + wlr_log(WLR_INFO, "got GPU!"); +// struct wlr_backend *drm = wlr_drm_backend_create(display, session, +// gpus[i], primary_drm, create_renderer_func); +// if (!drm) { +// wlr_log(WLR_ERROR, "Failed to open DRM device %d", gpus[i]); +// continue; +// } +// +// if (!primary_drm) { +// primary_drm = drm; +// } +// +// wlr_multi_backend_add(backend, drm); } } @@ -368,3 +428,36 @@ size_t wlr_session_find_gpus(struct wlr_session *session, return i; } + +int session_try_add_gpu(struct wlr_session *session, struct udev_device *udev_dev) { + bool is_boot_vga = false; + + const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT"); + if (!seat) { + seat = "seat0"; + } + if (session->seat[0] && strcmp(session->seat, seat) != 0) { + return -1; + } + + // This is owned by 'udev_dev', so we don't need to free it + struct udev_device *pci = + udev_device_get_parent_with_subsystem_devtype(udev_dev, "pci", NULL); + + if (pci) { + const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); + if (id && strcmp(id, "1") == 0) { + is_boot_vga = true; + } + } + + int fd = open_if_kms(session, udev_device_get_devnode(udev_dev)); + if (fd < 0) { + wlr_log(WLR_INFO, "failed to open device %s", udev_device_get_devnode(udev_dev)); + return fd; + } + + wlr_log(WLR_INFO, "isbootvga? %d", is_boot_vga); + + return fd; +} \ No newline at end of file diff --git a/include/backend/session/session.h b/include/backend/session/session.h index 626f470a3f..de22b4dfc1 100644 --- a/include/backend/session/session.h +++ b/include/backend/session/session.h @@ -4,5 +4,6 @@ struct wlr_session; void session_init(struct wlr_session *session); +int session_try_add_gpu(struct wlr_session *session, struct udev_device *udev_dev); #endif diff --git a/meson.build b/meson.build index ca26391e70..3d1138b160 100644 --- a/meson.build +++ b/meson.build @@ -110,6 +110,7 @@ udev = dependency('libudev') pixman = dependency('pixman-1') math = cc.find_library('m') rt = cc.find_library('rt') +backtrace = cc.find_library('backtrace') if cc.has_header('EGL/eglmesaext.h', dependencies: egl) conf_data.set10('WLR_HAS_EGLMESAEXT_H', true) @@ -131,6 +132,7 @@ wlr_deps = [ pixman, math, rt, + backtrace ] libinput_ver = libinput.version().split('.') @@ -194,4 +196,4 @@ pkgconfig.generate(lib_wlr, filebase: meson.project_name(), name: meson.project_name(), description: 'Wayland compositor library', -) +) \ No newline at end of file