[PATCH weston 2/2] compositor-drm: prefer primary GPU over other GPUs

David Herrmann dh.herrmann at googlemail.com
Sat Oct 27 05:54:43 PDT 2012


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 <dh.herrmann at googlemail.com>
---
 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



More information about the wayland-devel mailing list