This rewrites the GPU detection of the DRM backend and uses the new PCI helpers to find the primary GPU. If no primary GPU is found, the first GPU on the seat is used.
This is useful for systems with multiple GPUs that share display-controllers. We want to use the boot/primary GPU instead of possible offload-GPUs. Note that the kernel does not provide this information, yet, so we need to retrieve it via the PCI bus. It is also unclear whether the kernel will ever report this data as this is hardly possible to detect properly in the kernel. Signed-off-by: David Herrmann <[email protected]> --- src/compositor-drm.c | 117 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 28 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 3e75387..0fc9279 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -23,6 +23,8 @@ #define _GNU_SOURCE +#include "config.h" + #include <errno.h> #include <stdlib.h> #include <string.h> @@ -181,6 +183,19 @@ struct drm_seat { char *seat_id; }; +#ifdef HAVE_PCIACCESS + +char *weston_pci_get_primary_id(void); + +#else + +static inline char *weston_pci_get_primary_id(void) +{ + return NULL; +} + +#endif + static void drm_output_set_cursor(struct drm_output *output); static void @@ -2148,18 +2163,84 @@ switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data) tty_activate_vt(ec->tty, key - KEY_F1 + 1); } +static struct udev_device* +find_primary_gpu(struct drm_compositor *ec, const char *seat) +{ + char *primary_id, *id; + struct udev_enumerate *e; + struct udev_list_entry *entry; + const char *path, *device_seat, *node; + struct udev_device *device, *drm_device; + int fd; + + primary_id = weston_pci_get_primary_id(); + if (!primary_id) + weston_log("cannot determine primary PCI GPU\n"); + e = udev_enumerate_new(ec->udev); + udev_enumerate_add_match_subsystem(e, "drm"); + udev_enumerate_add_match_sysname(e, "card[0-9]*"); + + udev_enumerate_scan_devices(e); + drm_device = NULL; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { + path = udev_list_entry_get_name(entry); + device = udev_device_new_from_syspath(ec->udev, path); + if (!device) + continue; + node = udev_device_get_devnode(device); + if (!node) { + udev_device_unref(device); + continue; + } + device_seat = udev_device_get_property_value(device, "ID_SEAT"); + if (!device_seat) + device_seat = default_seat; + if (strcmp(device_seat, seat)) { + udev_device_unref(device); + continue; + } + + if (!primary_id) { + drm_device = device; + break; + } + + fd = open(node, O_RDWR | O_CLOEXEC); + if (fd < 0) { + udev_device_unref(device); + continue; + } + id = drmGetBusid(fd); + close(fd); + + if (id && !strcmp(id, primary_id)) { + drmFreeBusid(id); + if (drm_device) + udev_device_unref(drm_device); + drm_device = device; + break; + } else if (id) { + drmFreeBusid(id); + } + + if (!drm_device) + drm_device = device; + } + + udev_enumerate_unref(e); + return drm_device; +} + static struct weston_compositor * drm_compositor_create(struct wl_display *display, int connector, const char *seat, int tty, int argc, char *argv[], const char *config_file) { struct drm_compositor *ec; - struct udev_enumerate *e; - struct udev_list_entry *entry; - struct udev_device *device, *drm_device; - const char *path, *device_seat; + struct udev_device *drm_device; struct wl_event_loop *loop; struct weston_seat *weston_seat, *next; + const char *path; uint32_t key; weston_log("initializing drm backend\n"); @@ -2188,30 +2269,12 @@ drm_compositor_create(struct wl_display *display, goto err_udev; } - e = udev_enumerate_new(ec->udev); - udev_enumerate_add_match_subsystem(e, "drm"); - udev_enumerate_add_match_sysname(e, "card[0-9]*"); - - udev_enumerate_scan_devices(e); - drm_device = NULL; - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) { - path = udev_list_entry_get_name(entry); - device = udev_device_new_from_syspath(ec->udev, path); - device_seat = - udev_device_get_property_value(device, "ID_SEAT"); - if (!device_seat) - device_seat = default_seat; - if (strcmp(device_seat, seat) == 0) { - drm_device = device; - break; - } - udev_device_unref(device); - } - + drm_device = find_primary_gpu(ec, seat); if (drm_device == NULL) { weston_log("no drm device found\n"); - goto err_udev_enum; + goto err_tty; } + path = udev_device_get_syspath(drm_device); if (init_egl(ec, drm_device) < 0) { weston_log("failed to initialize egl\n"); @@ -2268,7 +2331,6 @@ drm_compositor_create(struct wl_display *display, } udev_device_unref(drm_device); - udev_enumerate_unref(e); return &ec->base; @@ -2289,8 +2351,7 @@ err_sprite: destroy_sprites(ec); err_udev_dev: udev_device_unref(drm_device); -err_udev_enum: - udev_enumerate_unref(e); +err_tty: tty_destroy(ec->tty); err_udev: udev_unref(ec->udev); -- 1.8.0 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
