[mutter] backends/native: Move KMS fd management to monitor manager



commit 16a6aef5a7a79f1897010f6db73534777a75c43c
Author: Jonas Ådahl <jadahl gmail com>
Date:   Thu Jul 6 16:00:56 2017 +0800

    backends/native: Move KMS fd management to monitor manager
    
    Move finding, opening and managment of the KMS file descriptor to
    MetaMonitorManagerKms. This means that the monitor manager creation can
    now fail, both if more than one GPU with connectors is discovered, or
    if finding or opening the primary GPU fails.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=785381

 src/backends/meta-backend-private.h               |    3 +-
 src/backends/meta-backend.c                       |   12 +-
 src/backends/native/meta-backend-native.c         |   31 ++-
 src/backends/native/meta-backend-native.h         |    3 +
 src/backends/native/meta-cursor-renderer-native.c |    6 +-
 src/backends/native/meta-launcher.c               |  310 +++++----------------
 src/backends/native/meta-launcher.h               |   10 +-
 src/backends/native/meta-monitor-manager-kms.c    |  272 +++++++++++++++++--
 src/backends/native/meta-monitor-manager-kms.h    |    2 +
 src/backends/native/meta-renderer-native.c        |  190 +++++++-------
 src/backends/native/meta-renderer-native.h        |    8 +-
 src/backends/x11/cm/meta-backend-x11-cm.c         |    3 +-
 src/backends/x11/nested/meta-backend-x11-nested.c |    3 +-
 src/tests/meta-backend-test.c                     |    3 +-
 14 files changed, 468 insertions(+), 388 deletions(-)
---
diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h
index fda36ed..0dc6bf7 100644
--- a/src/backends/meta-backend-private.h
+++ b/src/backends/meta-backend-private.h
@@ -61,7 +61,8 @@ struct _MetaBackendClass
 
   MetaIdleMonitor * (* create_idle_monitor) (MetaBackend *backend,
                                              int          device_id);
-  MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend);
+  MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend,
+                                                   GError     **error);
   MetaCursorRenderer * (* create_cursor_renderer) (MetaBackend *backend);
   MetaRenderer * (* create_renderer) (MetaBackend *backend,
                                       GError     **error);
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
index 42800b6..7571e6e 100644
--- a/src/backends/meta-backend.c
+++ b/src/backends/meta-backend.c
@@ -571,12 +571,14 @@ experimental_features_changed (MetaSettings            *settings,
 }
 
 static MetaMonitorManager *
-meta_backend_create_monitor_manager (MetaBackend *backend)
+meta_backend_create_monitor_manager (MetaBackend *backend,
+                                     GError     **error)
 {
   if (g_getenv ("META_DUMMY_MONITORS"))
     return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL);
 
-  return META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend);
+  return META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend,
+                                                                   error);
 }
 
 static MetaRenderer *
@@ -603,12 +605,14 @@ meta_backend_initable_init (GInitable     *initable,
 
   priv->orientation_manager = g_object_new (META_TYPE_ORIENTATION_MANAGER, NULL);
 
+  priv->monitor_manager = meta_backend_create_monitor_manager (backend, error);
+  if (!priv->monitor_manager)
+    return FALSE;
+
   priv->renderer = meta_backend_create_renderer (backend, error);
   if (!priv->renderer)
     return FALSE;
 
-  priv->monitor_manager = meta_backend_create_monitor_manager (backend);
-
   priv->cursor_tracker = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
 
   priv->dnd = g_object_new (META_TYPE_DND, NULL);
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index fb3392d..217f09b 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -400,9 +400,10 @@ meta_backend_native_create_idle_monitor (MetaBackend *backend,
 }
 
 static MetaMonitorManager *
-meta_backend_native_create_monitor_manager (MetaBackend *backend)
+meta_backend_native_create_monitor_manager (MetaBackend *backend,
+                                            GError     **error)
 {
-  return g_object_new (META_TYPE_MONITOR_MANAGER_KMS, NULL);
+  return g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error, NULL);
 }
 
 static MetaCursorRenderer *
@@ -415,16 +416,13 @@ static MetaRenderer *
 meta_backend_native_create_renderer (MetaBackend *backend,
                                      GError     **error)
 {
-  MetaBackendNative *native = META_BACKEND_NATIVE (backend);
-  MetaBackendNativePrivate *priv =
-    meta_backend_native_get_instance_private (native);
-  int kms_fd;
-  const char *kms_file_path;
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+  MetaMonitorManagerKms *monitor_manager_kms =
+    META_MONITOR_MANAGER_KMS (monitor_manager);
   MetaRendererNative *renderer_native;
 
-  kms_fd = meta_launcher_get_kms_fd (priv->launcher);
-  kms_file_path = meta_launcher_get_kms_file_path (priv->launcher);
-  renderer_native = meta_renderer_native_new (kms_fd, kms_file_path, error);
+  renderer_native = meta_renderer_native_new (monitor_manager_kms, error);
   if (!renderer_native)
     return NULL;
 
@@ -621,14 +619,23 @@ meta_backend_native_init (MetaBackendNative *native)
              native);
 }
 
+MetaLauncher *
+meta_backend_native_get_launcher (MetaBackendNative *native)
+{
+  MetaBackendNativePrivate *priv =
+    meta_backend_native_get_instance_private (native);
+
+  return priv->launcher;
+}
+
 gboolean
 meta_activate_vt (int vt, GError **error)
 {
   MetaBackend *backend = meta_get_backend ();
   MetaBackendNative *native = META_BACKEND_NATIVE (backend);
-  MetaBackendNativePrivate *priv = meta_backend_native_get_instance_private (native);
+  MetaLauncher *launcher = meta_backend_native_get_launcher (native);
 
-  return meta_launcher_activate_vt (priv->launcher, vt, error);
+  return meta_launcher_activate_vt (launcher, vt, error);
 }
 
 MetaBarrierManagerNative *
diff --git a/src/backends/native/meta-backend-native.h b/src/backends/native/meta-backend-native.h
index 3ba57a0..d69fbe0 100644
--- a/src/backends/native/meta-backend-native.h
+++ b/src/backends/native/meta-backend-native.h
@@ -27,6 +27,7 @@
 
 #include "backends/meta-backend-private.h"
 #include "backends/native/meta-clutter-backend-native.h"
+#include "backends/native/meta-launcher.h"
 
 #define META_TYPE_BACKEND_NATIVE (meta_backend_native_get_type ())
 G_DECLARE_FINAL_TYPE (MetaBackendNative, meta_backend_native,
@@ -38,4 +39,6 @@ void meta_backend_native_pause (MetaBackendNative *backend_native);
 
 void meta_backend_native_resume (MetaBackendNative *backend_native);
 
+MetaLauncher * meta_backend_native_get_launcher (MetaBackendNative *native);
+
 #endif /* META_BACKEND_NATIVE_H */
diff --git a/src/backends/native/meta-cursor-renderer-native.c 
b/src/backends/native/meta-cursor-renderer-native.c
index cb5686e..dc10e2e 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -862,8 +862,12 @@ meta_cursor_renderer_native_init (MetaCursorRendererNative *native)
       MetaBackend *backend = meta_get_backend ();
       MetaRenderer *renderer = meta_backend_get_renderer (backend);
       MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
+      MetaMonitorManager *monitor_manager =
+        meta_backend_get_monitor_manager (backend);
+      MetaMonitorManagerKms *monitor_manager_kms =
+        META_MONITOR_MANAGER_KMS (monitor_manager);
 
-      priv->drm_fd = meta_renderer_native_get_kms_fd (renderer_native);
+      priv->drm_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
       priv->gbm = meta_renderer_native_get_gbm (renderer_native);
 
       uint64_t width, height;
diff --git a/src/backends/native/meta-launcher.c b/src/backends/native/meta-launcher.c
index eb35f88..f655f0e 100644
--- a/src/backends/native/meta-launcher.c
+++ b/src/backends/native/meta-launcher.c
@@ -47,20 +47,22 @@
 #include "meta-idle-monitor-native.h"
 #include "meta-renderer-native.h"
 
-#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
-
 struct _MetaLauncher
 {
   Login1Session *session_proxy;
   Login1Seat *seat_proxy;
+  char *seat_id;
 
   GHashTable *sysfs_fds;
   gboolean session_active;
-
-  int kms_fd;
-  char *kms_file_path;
 };
 
+const char *
+meta_launcher_get_seat_id (MetaLauncher *launcher)
+{
+  return launcher->seat_id;
+}
+
 static Login1Session *
 get_session_proxy (GCancellable *cancellable,
                    GError      **error)
@@ -171,6 +173,54 @@ get_device_info_from_fd (int  fd,
   return TRUE;
 }
 
+int
+meta_launcher_open_restricted (MetaLauncher *launcher,
+                               const char   *path,
+                               GError      **error)
+{
+  int fd;
+  int major, minor;
+
+  if (!get_device_info_from_path (path, &major, &minor))
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_NOT_FOUND,
+                   "Could not get device info for path %s: %m", path);
+      return -1;
+    }
+
+  if (!take_device (launcher->session_proxy, major, minor, &fd, NULL, error))
+    return -1;
+
+  return fd;
+}
+
+void
+meta_launcher_close_restricted (MetaLauncher *launcher,
+                                int           fd)
+{
+  int major, minor;
+  GError *error = NULL;
+
+  if (!get_device_info_from_fd (fd, &major, &minor))
+    {
+      g_warning ("Could not get device info for fd %d: %m", fd);
+      goto out;
+    }
+
+  if (!login1_session_call_release_device_sync (launcher->session_proxy,
+                                                major, minor,
+                                                NULL, &error))
+    {
+      g_warning ("Could not release device (%d,%d): %s",
+                 major, minor, error->message);
+    }
+
+out:
+  close (fd);
+}
+
 static int
 on_evdev_device_open (const char  *path,
                       int          flags,
@@ -178,12 +228,12 @@ on_evdev_device_open (const char  *path,
                       GError     **error)
 {
   MetaLauncher *self = user_data;
-  int fd;
-  int major, minor;
 
   /* Allow readonly access to sysfs */
   if (g_str_has_prefix (path, "/sys/"))
     {
+      int fd;
+
       do
         {
           fd = open (path, flags);
@@ -203,19 +253,7 @@ on_evdev_device_open (const char  *path,
       return fd;
     }
 
-  if (!get_device_info_from_path (path, &major, &minor))
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_NOT_FOUND,
-                   "Could not get device info for path %s: %m", path);
-      return -1;
-    }
-
-  if (!take_device (self->session_proxy, major, minor, &fd, NULL, error))
-    return -1;
-
-  return fd;
+  return meta_launcher_open_restricted (self, path, error);
 }
 
 static void
@@ -223,8 +261,6 @@ on_evdev_device_close (int      fd,
                        gpointer user_data)
 {
   MetaLauncher *self = user_data;
-  int major, minor;
-  GError *error = NULL;
 
   if (g_hash_table_lookup (self->sysfs_fds, GINT_TO_POINTER (fd)))
     {
@@ -234,21 +270,7 @@ on_evdev_device_close (int      fd,
       return;
     }
 
-  if (!get_device_info_from_fd (fd, &major, &minor))
-    {
-      g_warning ("Could not get device info for fd %d: %m", fd);
-      goto out;
-    }
-
-  if (!login1_session_call_release_device_sync (self->session_proxy,
-                                                major, minor,
-                                                NULL, &error))
-    {
-      g_warning ("Could not release device %d,%d: %s", major, minor, error->message);
-    }
-
-out:
-  close (fd);
+  meta_launcher_close_restricted (self, fd);
 }
 
 static void
@@ -278,194 +300,6 @@ on_active_changed (Login1Session *session,
   sync_active (self);
 }
 
-static guint
-count_devices_with_connectors (const gchar *seat_name,
-                               GList       *devices)
-{
-  g_autoptr (GHashTable) cards = NULL;
-  GList *tmp;
-
-  cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
-  for (tmp = devices; tmp != NULL; tmp = tmp->next)
-    {
-      GUdevDevice *device = tmp->data;
-      g_autoptr (GUdevDevice) parent_device = NULL;
-      const gchar *parent_device_type = NULL;
-      const gchar *parent_device_name = NULL;
-      const gchar *card_seat;
-
-      /* filter out the real card devices, we only care about the connectors */
-      if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE)
-        continue;
-
-      /* only connectors have a modes attribute */
-      if (!g_udev_device_has_sysfs_attr (device, "modes"))
-        continue;
-
-      parent_device = g_udev_device_get_parent (device);
-
-      if (g_udev_device_get_device_type (parent_device) == G_UDEV_DEVICE_TYPE_CHAR)
-        parent_device_type = g_udev_device_get_property (parent_device, "DEVTYPE");
-
-      if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
-        continue;
-
-      card_seat = g_udev_device_get_property (parent_device, "ID_SEAT");
-
-      if (!card_seat)
-        card_seat = "seat0";
-
-      if (g_strcmp0 (seat_name, card_seat) != 0)
-        continue;
-
-      parent_device_name = g_udev_device_get_name (parent_device);
-      g_hash_table_insert (cards,
-                           (gpointer) parent_device_name ,
-                           g_steal_pointer (&parent_device));
-    }
-
-  return g_hash_table_size (cards);
-}
-
-static gchar *
-get_primary_gpu_path (const gchar *seat_name)
-{
-  const gchar *subsystems[] = {"drm", NULL};
-  gchar *path = NULL;
-  GList *devices, *tmp;
-
-  g_autoptr (GUdevClient) gudev_client = g_udev_client_new (subsystems);
-  g_autoptr (GUdevEnumerator) enumerator = g_udev_enumerator_new (gudev_client);
-
-  g_udev_enumerator_add_match_name (enumerator, "card*");
-  g_udev_enumerator_add_match_tag (enumerator, "seat");
-
-  /* We need to explicitly match the subsystem for now.
-   * https://bugzilla.gnome.org/show_bug.cgi?id=773224
-   */
-  g_udev_enumerator_add_match_subsystem (enumerator, "drm");
-
-  devices = g_udev_enumerator_execute (enumerator);
-  if (!devices)
-    goto out;
-
-  /* For now, fail on systems where some of the connectors
-   * are connected to secondary gpus.
-   *
-   * https://bugzilla.gnome.org/show_bug.cgi?id=771442
-   */
-  if (g_getenv ("MUTTER_ALLOW_HYBRID_GPUS") == NULL)
-    {
-      guint num_devices;
-
-      num_devices = count_devices_with_connectors (seat_name, devices);
-      if (num_devices != 1)
-        goto out;
-    }
-
-  for (tmp = devices; tmp != NULL; tmp = tmp->next)
-    {
-      g_autoptr (GUdevDevice) platform_device = NULL;
-      g_autoptr (GUdevDevice) pci_device = NULL;
-      GUdevDevice *dev = tmp->data;
-      gint boot_vga;
-      const gchar *device_type;
-      const gchar *device_seat;
-
-      /* filter out devices that are not character device, like card0-VGA-1 */
-      if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
-        continue;
-
-      device_type = g_udev_device_get_property (dev, "DEVTYPE");
-      if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
-        continue;
-
-      device_seat = g_udev_device_get_property (dev, "ID_SEAT");
-      if (!device_seat)
-        {
-          /* when ID_SEAT is not set, it means seat0 */
-          device_seat = "seat0";
-        }
-      else if (g_strcmp0 (device_seat, "seat0") != 0)
-        {
-          /* if the device has been explicitly assigned other seat
-           * than seat0, it is probably the right device to use */
-          path = g_strdup (g_udev_device_get_device_file (dev));
-          break;
-        }
-
-      /* skip devices that do not belong to our seat */
-      if (g_strcmp0 (seat_name, device_seat))
-        continue;
-
-      platform_device = g_udev_device_get_parent_with_subsystem (dev, "platform", NULL);
-      if (platform_device != NULL)
-        {
-          path = g_strdup (g_udev_device_get_device_file (dev));
-          break;
-        }
-
-      pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
-      if (pci_device != NULL)
-        {
-          /* get value of boot_vga attribute or 0 if the device has no boot_vga */
-          boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device, "boot_vga");
-          if (boot_vga == 1)
-            {
-              /* found the boot_vga device */
-              path = g_strdup (g_udev_device_get_device_file (dev));
-              break;
-            }
-        }
-    }
-
-out:
-  g_list_free_full (devices, g_object_unref);
-
-  return path;
-}
-
-static gboolean
-get_kms_fd (Login1Session *session_proxy,
-            const gchar   *seat_id,
-            int           *fd_out,
-            char         **kms_file_path_out,
-            GError       **error)
-{
-  int major, minor;
-  int fd;
-
-  g_autofree gchar *path = get_primary_gpu_path (seat_id);
-  if (!path)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_NOT_FOUND,
-                   "could not find drm kms device");
-      return FALSE;
-    }
-
-  if (!get_device_info_from_path (path, &major, &minor))
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_NOT_FOUND,
-                   "Could not get device info for path %s: %m", path);
-      return FALSE;
-    }
-
-  if (!take_device (session_proxy, major, minor, &fd, NULL, error))
-    {
-      g_prefix_error (error, "Could not open DRM device: ");
-      return FALSE;
-    }
-
-  *fd_out = fd;
-  *kms_file_path_out = g_steal_pointer (&path);
-
-  return TRUE;
-}
-
 static gchar *
 get_seat_id (GError **error)
 {
@@ -504,8 +338,6 @@ meta_launcher_new (GError **error)
   g_autoptr (Login1Seat) seat_proxy = NULL;
   g_autofree char *seat_id = NULL;
   gboolean have_control = FALSE;
-  int kms_fd;
-  char *kms_file_path;
 
   session_proxy = get_session_proxy (NULL, error);
   if (!session_proxy)
@@ -527,25 +359,21 @@ meta_launcher_new (GError **error)
   if (!seat_proxy)
     goto fail;
 
-  if (!get_kms_fd (session_proxy, seat_id, &kms_fd, &kms_file_path, error))
-    goto fail;
-
   self = g_slice_new0 (MetaLauncher);
   self->session_proxy = g_object_ref (session_proxy);
   self->seat_proxy = g_object_ref (seat_proxy);
+  self->seat_id = g_steal_pointer (&seat_id);
   self->sysfs_fds = g_hash_table_new (NULL, NULL);
-
   self->session_active = TRUE;
-  self->kms_fd = kms_fd;
-  self->kms_file_path = kms_file_path;
 
-  clutter_evdev_set_seat_id (seat_id);
+  clutter_evdev_set_seat_id (self->seat_id);
 
   clutter_evdev_set_device_callbacks (on_evdev_device_open,
                                       on_evdev_device_close,
                                       self);
 
   g_signal_connect (self->session_proxy, "notify::active", G_CALLBACK (on_active_changed), self);
+
   return self;
 
  fail:
@@ -557,10 +385,10 @@ meta_launcher_new (GError **error)
 void
 meta_launcher_free (MetaLauncher *self)
 {
+  g_free (self->seat_id);
   g_object_unref (self->seat_proxy);
   g_object_unref (self->session_proxy);
   g_hash_table_destroy (self->sysfs_fds);
-  g_free (self->kms_file_path);
   g_slice_free (MetaLauncher, self);
 }
 
@@ -582,15 +410,3 @@ meta_launcher_activate_vt (MetaLauncher  *launcher,
 {
   return login1_seat_call_switch_to_sync (launcher->seat_proxy, vt, NULL, error);
 }
-
-int
-meta_launcher_get_kms_fd (MetaLauncher *self)
-{
-  return self->kms_fd;
-}
-
-const char *
-meta_launcher_get_kms_file_path (MetaLauncher *self)
-{
-  return self->kms_file_path;
-}
diff --git a/src/backends/native/meta-launcher.h b/src/backends/native/meta-launcher.h
index 4b16e35..d83cf81 100644
--- a/src/backends/native/meta-launcher.h
+++ b/src/backends/native/meta-launcher.h
@@ -34,8 +34,14 @@ gboolean          meta_launcher_activate_vt             (MetaLauncher  *self,
                                                         signed char    vt,
                                                         GError       **error);
 
-int               meta_launcher_get_kms_fd              (MetaLauncher  *self);
+const char *      meta_launcher_get_seat_id             (MetaLauncher *launcher);
+
+int               meta_launcher_open_restricted         (MetaLauncher *launcher,
+                                                         const char   *path,
+                                                         GError      **error);
+
+void              meta_launcher_close_restricted        (MetaLauncher *launcher,
+                                                         int           fd);
 
-const char *      meta_launcher_get_kms_file_path       (MetaLauncher *self);
 
 #endif /* META_LAUNCHER_H */
diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-kms.c
index b58f5c3..8d4362b 100644
--- a/src/backends/native/meta-monitor-manager-kms.c
+++ b/src/backends/native/meta-monitor-manager-kms.c
@@ -25,7 +25,9 @@
 
 #include "meta-monitor-manager-kms.h"
 #include "meta-monitor-config-manager.h"
+#include "meta-backend-native.h"
 #include "meta-crtc.h"
+#include "meta-launcher.h"
 #include "meta-output.h"
 #include "meta-backend-private.h"
 #include "meta-renderer-native.h"
@@ -49,6 +51,8 @@
 
 #include "meta-default-modes.h"
 
+#define DRM_CARD_UDEV_DEVICE_TYPE "drm_minor"
+
 typedef struct
 {
   GSource source;
@@ -62,6 +66,7 @@ struct _MetaMonitorManagerKms
   MetaMonitorManager parent_instance;
 
   int fd;
+  char *file_path;
   MetaKmsSource *source;
 
   drmModeConnector **connectors;
@@ -81,7 +86,13 @@ struct _MetaMonitorManagerKmsClass
   MetaMonitorManagerClass parent_class;
 };
 
-G_DEFINE_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, META_TYPE_MONITOR_MANAGER);
+static void
+initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerKms, meta_monitor_manager_kms,
+                         META_TYPE_MONITOR_MANAGER,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                initable_iface_init))
 
 int
 meta_monitor_manager_kms_get_fd (MetaMonitorManagerKms *manager_kms)
@@ -89,6 +100,12 @@ meta_monitor_manager_kms_get_fd (MetaMonitorManagerKms *manager_kms)
   return manager_kms->fd;
 }
 
+const char *
+meta_monitor_manager_kms_get_file_path (MetaMonitorManagerKms *manager_kms)
+{
+  return manager_kms->file_path;
+}
+
 static void
 free_resources (MetaMonitorManagerKms *manager_kms)
 {
@@ -1076,41 +1093,216 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager)
     return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL;
 }
 
-static void
-meta_monitor_manager_kms_dispose (GObject *object)
+static guint
+count_devices_with_connectors (const char *seat_id,
+                               GList      *devices)
 {
-  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
+  g_autoptr (GHashTable) cards = NULL;
+  GList *l;
 
-  g_clear_object (&manager_kms->udev);
+  cards = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
+  for (l = devices; l != NULL; l = l->next)
+    {
+      GUdevDevice *device = l->data;
+      g_autoptr (GUdevDevice) parent_device = NULL;
+      const gchar *parent_device_type = NULL;
+      const gchar *parent_device_name = NULL;
+      const gchar *card_seat;
 
-  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
+      /* Filter out the real card devices, we only care about the connectors. */
+      if (g_udev_device_get_device_type (device) != G_UDEV_DEVICE_TYPE_NONE)
+        continue;
+
+      /* Only connectors have a modes attribute. */
+      if (!g_udev_device_has_sysfs_attr (device, "modes"))
+        continue;
+
+      parent_device = g_udev_device_get_parent (device);
+
+      if (g_udev_device_get_device_type (parent_device) ==
+          G_UDEV_DEVICE_TYPE_CHAR)
+        parent_device_type = g_udev_device_get_property (parent_device,
+                                                         "DEVTYPE");
+
+      if (g_strcmp0 (parent_device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
+        continue;
+
+      card_seat = g_udev_device_get_property (parent_device, "ID_SEAT");
+
+      if (!card_seat)
+        card_seat = "seat0";
+
+      if (g_strcmp0 (seat_id, card_seat) != 0)
+        continue;
+
+      parent_device_name = g_udev_device_get_name (parent_device);
+      g_hash_table_insert (cards,
+                           (gpointer) parent_device_name ,
+                           g_steal_pointer (&parent_device));
+    }
+
+  return g_hash_table_size (cards);
 }
 
-static void
-meta_monitor_manager_kms_finalize (GObject *object)
+static char *
+get_primary_gpu_path (MetaMonitorManagerKms *manager_kms)
 {
-  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
+  MetaBackend *backend = meta_get_backend ();
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
+  g_autoptr (GUdevEnumerator) enumerator = NULL;
+  const char *seat_id;
+  char *path = NULL;
+  GList *devices;
+  GList *l;
 
-  free_resources (manager_kms);
-  g_source_destroy ((GSource *) manager_kms->source);
+  enumerator = g_udev_enumerator_new (manager_kms->udev);
 
-  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
+  g_udev_enumerator_add_match_name (enumerator, "card*");
+  g_udev_enumerator_add_match_tag (enumerator, "seat");
+
+  /*
+   * We need to explicitly match the subsystem for now.
+   * https://bugzilla.gnome.org/show_bug.cgi?id=773224
+   */
+  g_udev_enumerator_add_match_subsystem (enumerator, "drm");
+
+  devices = g_udev_enumerator_execute (enumerator);
+  if (!devices)
+    goto out;
+
+  seat_id = meta_launcher_get_seat_id (launcher);
+
+  /*
+   * For now, fail on systems where some of the connectors are connected to
+   * secondary gpus.
+   *
+   * https://bugzilla.gnome.org/show_bug.cgi?id=771442
+   */
+  if (g_getenv ("MUTTER_ALLOW_HYBRID_GPUS") == NULL)
+    {
+      unsigned int num_devices;
+
+      num_devices = count_devices_with_connectors (seat_id, devices);
+      if (num_devices != 1)
+        goto out;
+    }
+
+  for (l = devices; l; l = l->next)
+    {
+      GUdevDevice *dev = l->data;
+      g_autoptr (GUdevDevice) platform_device = NULL;
+      g_autoptr (GUdevDevice) pci_device = NULL;
+      const char *device_type;
+      const char *device_seat;
+
+      /* Filter out devices that are not character device, like card0-VGA-1. */
+      if (g_udev_device_get_device_type (dev) != G_UDEV_DEVICE_TYPE_CHAR)
+        continue;
+
+      device_type = g_udev_device_get_property (dev, "DEVTYPE");
+      if (g_strcmp0 (device_type, DRM_CARD_UDEV_DEVICE_TYPE) != 0)
+        continue;
+
+      device_seat = g_udev_device_get_property (dev, "ID_SEAT");
+      if (!device_seat)
+        {
+          /* When ID_SEAT is not set, it means seat0. */
+          device_seat = "seat0";
+        }
+      else if (g_strcmp0 (device_seat, "seat0") != 0)
+        {
+          /*
+           * If the device has been explicitly assigned other seat
+           * than seat0, it is probably the right device to use.
+           */
+          path = g_strdup (g_udev_device_get_device_file (dev));
+          break;
+        }
+
+      /* Skip devices that do not belong to our seat. */
+      if (g_strcmp0 (seat_id, device_seat))
+        continue;
+
+      platform_device = g_udev_device_get_parent_with_subsystem (dev,
+                                                                 "platform",
+                                                                 NULL);
+      if (platform_device != NULL)
+        {
+          path = g_strdup (g_udev_device_get_device_file (dev));
+          break;
+        }
+
+      pci_device = g_udev_device_get_parent_with_subsystem (dev, "pci", NULL);
+      if (pci_device != NULL)
+        {
+          int boot_vga;
+
+          boot_vga = g_udev_device_get_sysfs_attr_as_int (pci_device,
+                                                          "boot_vga");
+          if (boot_vga == 1)
+            {
+              path = g_strdup (g_udev_device_get_device_file (dev));
+              break;
+            }
+        }
+    }
+
+out:
+  g_list_free_full (devices, g_object_unref);
+
+  return path;
 }
 
-static void
-meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
+static gboolean
+open_primary_gpu (MetaMonitorManagerKms *manager_kms,
+                  int                   *fd_out,
+                  char                 **kms_file_path_out,
+                  GError               **error)
 {
   MetaBackend *backend = meta_get_backend ();
-  MetaRenderer *renderer = meta_backend_get_renderer (backend);
-  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
-  GSource *source;
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
+  g_autofree char *path = NULL;
+  int fd;
+
+  path = get_primary_gpu_path (manager_kms);
+  if (!path)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                   "Could not find drm kms device");
+      return FALSE;
+    }
 
-  manager_kms->fd = meta_renderer_native_get_kms_fd (renderer_native);
+  fd = meta_launcher_open_restricted (launcher, path, error);
+  if (fd == -1)
+    return FALSE;
 
-  drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+  *fd_out = fd;
+  *kms_file_path_out = g_steal_pointer (&path);
 
+  return TRUE;
+}
+
+static gboolean
+meta_monitor_manager_kms_initable_init (GInitable    *initable,
+                                        GCancellable *cancellable,
+                                        GError      **error)
+{
+  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (initable);
+  GSource *source;
   const char *subsystems[2] = { "drm", NULL };
+
   manager_kms->udev = g_udev_client_new (subsystems);
+
+  if (!open_primary_gpu (manager_kms,
+                         &manager_kms->fd,
+                         &manager_kms->file_path,
+                         error))
+    return FALSE;
+
+  drmSetClientCap (manager_kms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+
   meta_monitor_manager_kms_connect_uevent_handler (manager_kms);
 
   source = g_source_new (&kms_event_funcs, sizeof (MetaKmsSource));
@@ -1120,6 +1312,48 @@ meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
                                                       G_IO_IN | G_IO_ERR);
   manager_kms->source->manager_kms = manager_kms;
   g_source_attach (source, NULL);
+
+  return TRUE;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+  initable_iface->init = meta_monitor_manager_kms_initable_init;
+}
+
+static void
+meta_monitor_manager_kms_dispose (GObject *object)
+{
+  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
+
+  g_clear_object (&manager_kms->udev);
+
+  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object);
+}
+
+static void
+meta_monitor_manager_kms_finalize (GObject *object)
+{
+  MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object);
+  MetaBackend *backend = meta_get_backend ();
+  MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
+  MetaLauncher *launcher = meta_backend_native_get_launcher (backend_native);
+
+  if (manager_kms->fd != -1)
+    meta_launcher_close_restricted (launcher, manager_kms->fd);
+  g_clear_pointer (&manager_kms->file_path, g_free);
+
+  free_resources (manager_kms);
+  g_source_destroy ((GSource *) manager_kms->source);
+
+  G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->finalize (object);
+}
+
+static void
+meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms)
+{
+  manager_kms->fd = -1;
 }
 
 static void
diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-kms.h
index 67ccbfe..e4e71b1 100644
--- a/src/backends/native/meta-monitor-manager-kms.h
+++ b/src/backends/native/meta-monitor-manager-kms.h
@@ -44,6 +44,8 @@ typedef void (*MetaKmsFlipCallback) (void *user_data);
 
 int meta_monitor_manager_kms_get_fd (MetaMonitorManagerKms *manager_kms);
 
+const char * meta_monitor_manager_kms_get_file_path (MetaMonitorManagerKms *manager_kms);
+
 gboolean meta_drm_mode_equal (const drmModeModeInfo *one,
                               const drmModeModeInfo *two);
 
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index d2a6c03..c85f3fe 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -67,12 +67,13 @@ enum
 {
   PROP_0,
 
-  PROP_KMS_FD,
-  PROP_KMS_FILE_PATH,
+  PROP_MONITOR_MANAGER,
 
   PROP_LAST
 };
 
+static GParamSpec *obj_props[PROP_LAST];
+
 typedef struct _MetaOnscreenNative
 {
   struct {
@@ -112,8 +113,7 @@ struct _MetaRendererNative
 {
   MetaRenderer parent;
 
-  int kms_fd;
-  char *kms_file_path;
+  MetaMonitorManagerKms *monitor_manager_kms;
 
   MetaRendererNativeMode mode;
 
@@ -224,11 +224,15 @@ free_current_bo (CoglOnscreen *onscreen)
   CoglRenderer *cogl_renderer = cogl_context->display->renderer;
   CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
   MetaRendererNative *renderer_native = egl_renderer->platform;
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
+  int kms_fd;
+
+  kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
 
   if (onscreen_native->gbm.current_fb_id)
     {
-      drmModeRmFB (renderer_native->kms_fd,
-                   onscreen_native->gbm.current_fb_id);
+      drmModeRmFB (kms_fd, onscreen_native->gbm.current_fb_id);
       onscreen_native->gbm.current_fb_id = 0;
     }
   if (onscreen_native->gbm.current_bo)
@@ -499,7 +503,12 @@ flip_closure_destroyed (MetaRendererView *view)
     case META_RENDERER_NATIVE_MODE_GBM:
       if (onscreen_native->gbm.next_fb_id)
         {
-          drmModeRmFB (renderer_native->kms_fd, onscreen_native->gbm.next_fb_id);
+          MetaMonitorManagerKms *monitor_manager_kms =
+            renderer_native->monitor_manager_kms;
+          int kms_fd;
+
+          kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
+          drmModeRmFB (kms_fd, onscreen_native->gbm.next_fb_id);
           gbm_surface_release_buffer (onscreen_native->gbm.surface,
                                       onscreen_native->gbm.next_bo);
           onscreen_native->gbm.next_bo = NULL;
@@ -581,10 +590,8 @@ meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
   MetaBackend *backend = meta_get_backend ();
   MetaRenderer *renderer = meta_backend_get_renderer (backend);
   MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
   MetaMonitorManagerKms *monitor_manager_kms =
-    META_MONITOR_MANAGER_KMS (monitor_manager);
+    renderer_native->monitor_manager_kms;
 
   if (!meta_monitor_manager_kms_is_crtc_active (monitor_manager_kms,
                                                 crtc))
@@ -618,7 +625,7 @@ meta_onscreen_native_flip_crtc (MetaOnscreenNative *onscreen_native,
 
 typedef struct _SetCrtcFbData
 {
-  MetaMonitorManager *monitor_manager;
+  MetaMonitorManagerKms *monitor_manager_kms;
   MetaLogicalMonitor *logical_monitor;
   uint32_t fb_id;
 } SetCrtcFbData;
@@ -629,8 +636,7 @@ set_crtc_fb (MetaLogicalMonitor *logical_monitor,
              gpointer            user_data)
 {
   SetCrtcFbData *data = user_data;
-  MetaMonitorManagerKms *monitor_manager_kms =
-    META_MONITOR_MANAGER_KMS (data->monitor_manager);
+  MetaMonitorManagerKms *monitor_manager_kms = data->monitor_manager_kms;
   int x, y;
 
   x = crtc->rect.x - logical_monitor->rect.x;
@@ -648,10 +654,8 @@ meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
   MetaBackend *backend = meta_get_backend ();
   MetaRenderer *renderer = meta_backend_get_renderer (backend);
   MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
   MetaMonitorManagerKms *monitor_manager_kms =
-    META_MONITOR_MANAGER_KMS (monitor_manager);
+    renderer_native->monitor_manager_kms;
   MetaRendererView *view = onscreen_native->view;
   uint32_t fb_id = 0;
   MetaLogicalMonitor *logical_monitor;
@@ -674,8 +678,8 @@ meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
   if (logical_monitor)
     {
       SetCrtcFbData data = {
-          .monitor_manager = monitor_manager,
-          .fb_id = fb_id
+        .monitor_manager_kms = monitor_manager_kms,
+        .fb_id = fb_id
       };
 
       meta_logical_monitor_foreach_crtc (logical_monitor,
@@ -684,6 +688,8 @@ meta_onscreen_native_set_crtc_modes (MetaOnscreenNative *onscreen_native)
     }
   else
     {
+      MetaMonitorManager *monitor_manager =
+        META_MONITOR_MANAGER (monitor_manager_kms);
       GList *crtcs;
       GList *l;
 
@@ -730,10 +736,13 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
 {
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
-  MetaBackend *backend = meta_get_backend ();
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
   MetaRendererView *view = onscreen_native->view;
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *cogl_context = framebuffer->context;
+  CoglDisplay *cogl_display = cogl_context->display;
+  CoglRenderer *cogl_renderer = cogl_display->renderer;
+  CoglRendererEGL *egl_renderer = cogl_renderer->winsys;
+  MetaRendererNative *renderer_native = egl_renderer->platform;
   GClosure *flip_closure;
   MetaLogicalMonitor *logical_monitor;
   gboolean fb_in_use = FALSE;
@@ -771,6 +780,8 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
     }
   else
     {
+      MetaMonitorManager *monitor_manager =
+        META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
       GList *crtcs;
       GList *l;
 
@@ -793,9 +804,6 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
    */
   if (fb_in_use && onscreen_native->pending_flips == 0)
     {
-      MetaRenderer *renderer = meta_backend_get_renderer (backend);
-      MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
-
       switch (renderer_native->mode)
         {
         case META_RENDERER_NATIVE_MODE_GBM:
@@ -824,9 +832,12 @@ gbm_get_next_fb_id (CoglOnscreen   *onscreen,
   MetaRendererNative *renderer_native = egl_renderer->platform;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
   uint32_t handle, stride;
   struct gbm_bo *next_bo;
   uint32_t next_fb_id;
+  int kms_fd;
 
   /* Now we need to set the CRTC to whatever is the front buffer */
   next_bo = gbm_surface_lock_front_buffer (onscreen_native->gbm.surface);
@@ -834,7 +845,9 @@ gbm_get_next_fb_id (CoglOnscreen   *onscreen,
   stride = gbm_bo_get_stride (next_bo);
   handle = gbm_bo_get_handle (next_bo).u32;
 
-  if (drmModeAddFB (renderer_native->kms_fd,
+  kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
+
+  if (drmModeAddFB (kms_fd,
                     cogl_framebuffer_get_width (COGL_FRAMEBUFFER (onscreen)),
                     cogl_framebuffer_get_height (COGL_FRAMEBUFFER (onscreen)),
                     24, /* depth */
@@ -864,11 +877,8 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen,
   MetaRendererNative *renderer_native = egl_renderer->platform;
   CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
   MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
-  MetaBackend *backend = meta_get_backend ();
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
   MetaMonitorManagerKms *monitor_manager_kms =
-    META_MONITOR_MANAGER_KMS (monitor_manager);
+    renderer_native->monitor_manager_kms;
   CoglFrameInfo *frame_info;
 
   frame_info = g_queue_peek_tail (&onscreen->pending_frame_infos);
@@ -1106,19 +1116,23 @@ init_dumb_fb (MetaRendererNative *renderer_native,
               int                 height,
               GError            **error)
 {
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
   struct drm_mode_create_dumb create_arg;
   struct drm_mode_destroy_dumb destroy_arg;
   struct drm_mode_map_dumb map_arg;
   uint32_t fb_id = 0;
   void *map;
+  int kms_fd;
+
+  kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
 
   create_arg = (struct drm_mode_create_dumb) {
     .bpp = 32, /* RGBX8888 */
     .width = width,
     .height = height
   };
-  if (drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_CREATE_DUMB,
-                &create_arg) != 0)
+  if (drmIoctl (kms_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg) != 0)
     {
       g_set_error (error, G_IO_ERROR,
                    G_IO_ERROR_FAILED,
@@ -1133,7 +1147,7 @@ init_dumb_fb (MetaRendererNative *renderer_native,
       uint32_t pitches[4] = { create_arg.pitch, };
       uint32_t offsets[4] = { 0 };
 
-      if (drmModeAddFB2 (renderer_native->kms_fd, width, height,
+      if (drmModeAddFB2 (kms_fd, width, height,
                          GBM_FORMAT_XRGB8888,
                          handles, pitches, offsets,
                          &fb_id, 0) != 0)
@@ -1146,7 +1160,7 @@ init_dumb_fb (MetaRendererNative *renderer_native,
 
   if (renderer_native->no_add_fb2)
     {
-      if (drmModeAddFB (renderer_native->kms_fd, width, height,
+      if (drmModeAddFB (kms_fd, width, height,
                         24 /* depth of RGBX8888 */,
                         32 /* bpp of RGBX8888 */,
                         create_arg.pitch,
@@ -1164,7 +1178,7 @@ init_dumb_fb (MetaRendererNative *renderer_native,
   map_arg = (struct drm_mode_map_dumb) {
     .handle = create_arg.handle
   };
-  if (drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_MAP_DUMB,
+  if (drmIoctl (kms_fd, DRM_IOCTL_MODE_MAP_DUMB,
                 &map_arg) != 0)
     {
       g_set_error (error, G_IO_ERROR,
@@ -1175,8 +1189,7 @@ init_dumb_fb (MetaRendererNative *renderer_native,
     }
 
   map = mmap (NULL, create_arg.size, PROT_WRITE, MAP_SHARED,
-              renderer_native->kms_fd,
-              map_arg.offset);
+              kms_fd, map_arg.offset);
   if (map == MAP_FAILED)
     {
       g_set_error (error, G_IO_ERROR,
@@ -1195,13 +1208,13 @@ init_dumb_fb (MetaRendererNative *renderer_native,
 
 err_mmap:
 err_map_dumb:
-  drmModeRmFB (renderer_native->kms_fd, fb_id);
+  drmModeRmFB (kms_fd, fb_id);
 
 err_add_fb:
   destroy_arg = (struct drm_mode_destroy_dumb) {
     .handle = create_arg.handle
   };
-  drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+  drmIoctl (kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
 
 err_ioctl:
   return FALSE;
@@ -1211,7 +1224,10 @@ static void
 release_dumb_fb (MetaRendererNative *renderer_native,
                  MetaOnscreenNative *onscreen_native)
 {
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
   struct drm_mode_destroy_dumb destroy_arg;
+  int kms_fd;
 
   if (!onscreen_native->egl.dumb_fb.map)
     return;
@@ -1220,13 +1236,14 @@ release_dumb_fb (MetaRendererNative *renderer_native,
           onscreen_native->egl.dumb_fb.map_size);
   onscreen_native->egl.dumb_fb.map = NULL;
 
-  drmModeRmFB (renderer_native->kms_fd,
-               onscreen_native->egl.dumb_fb.fb_id);
+  kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
+
+  drmModeRmFB (kms_fd, onscreen_native->egl.dumb_fb.fb_id);
 
   destroy_arg = (struct drm_mode_destroy_dumb) {
     .handle = onscreen_native->egl.dumb_fb.handle
   };
-  drmIoctl (renderer_native->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+  drmIoctl (kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
 }
 #endif /* HAVE_EGL_DEVICE */
 
@@ -1417,12 +1434,6 @@ meta_renderer_native_get_gbm (MetaRendererNative *renderer_native)
   return renderer_native->gbm.device;
 }
 
-int
-meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native)
-{
-  return renderer_native->kms_fd;
-}
-
 void
 meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
 {
@@ -1532,11 +1543,8 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
 
   if (width != view_layout.width || height != view_layout.height)
     {
-      MetaBackend *backend = meta_get_backend ();
-      MetaMonitorManager *monitor_manager =
-        meta_backend_get_monitor_manager (backend);
       MetaMonitorManagerKms *monitor_manager_kms =
-        META_MONITOR_MANAGER_KMS (monitor_manager);
+        renderer_native->monitor_manager_kms;
       CoglFramebuffer *framebuffer =
         clutter_stage_view_get_onscreen (stage_view);
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
@@ -1669,19 +1677,16 @@ meta_onscreen_native_set_view (CoglOnscreen     *onscreen,
 MetaRendererView *
 meta_renderer_native_create_legacy_view (MetaRendererNative *renderer_native)
 {
-  MetaBackend *backend = meta_get_backend ();
   MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
+    META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
   CoglOnscreen *onscreen = NULL;
+  MetaBackend *backend = meta_get_backend ();
   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
   CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
   cairo_rectangle_int_t view_layout = { 0 };
   MetaRendererView *view;
   GError *error = NULL;
 
-  if (!monitor_manager)
-    return NULL;
-
   meta_monitor_manager_get_screen_size (monitor_manager,
                                         &view_layout.width,
                                         &view_layout.height);
@@ -1742,9 +1747,10 @@ static MetaRendererView *
 meta_renderer_native_create_view (MetaRenderer       *renderer,
                                   MetaLogicalMonitor *logical_monitor)
 {
-  MetaBackend *backend = meta_get_backend ();
+  MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
   MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
+    META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
+  MetaBackend *backend = meta_get_backend ();
   ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
   CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
   CoglDisplay *cogl_display = cogl_context_get_display (cogl_context);
@@ -1867,11 +1873,8 @@ meta_renderer_native_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_KMS_FD:
-      g_value_set_int (value, renderer_native->kms_fd);
-      break;
-    case PROP_KMS_FILE_PATH:
-      g_value_set_string (value, renderer_native->kms_file_path);
+    case PROP_MONITOR_MANAGER:
+      g_value_set_object (value, renderer_native->monitor_manager_kms);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1889,11 +1892,8 @@ meta_renderer_native_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_KMS_FD:
-      renderer_native->kms_fd = g_value_get_int (value);
-      break;
-    case PROP_KMS_FILE_PATH:
-      renderer_native->kms_file_path = g_strdup (g_value_get_string (value));
+    case PROP_MONITOR_MANAGER:
+      renderer_native->monitor_manager_kms = g_value_get_object (value);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1908,8 +1908,6 @@ meta_renderer_native_finalize (GObject *object)
 
   g_clear_pointer (&renderer_native->gbm.device, gbm_device_destroy);
 
-  g_free (renderer_native->kms_file_path);
-
   G_OBJECT_CLASS (meta_renderer_native_parent_class)->finalize (object);
 }
 
@@ -1917,10 +1915,13 @@ static gboolean
 init_gbm (MetaRendererNative *renderer_native,
           GError            **error)
 {
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
   MetaBackend *backend = meta_get_backend ();
   MetaEgl *egl = meta_backend_get_egl (backend);
   struct gbm_device *gbm_device;
   EGLDisplay egl_display;
+  int kms_fd;
 
   if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
                                 "EGL_MESA_platform_gbm",
@@ -1932,7 +1933,9 @@ init_gbm (MetaRendererNative *renderer_native,
       return FALSE;
     }
 
-  gbm_device = gbm_create_device (renderer_native->kms_fd);
+  kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
+
+  gbm_device = gbm_create_device (kms_fd);
   if (!gbm_device)
     {
       g_set_error (error, G_IO_ERROR,
@@ -1983,11 +1986,14 @@ static EGLDeviceEXT
 find_egl_device (MetaRendererNative *renderer_native,
                  GError            **error)
 {
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
   MetaBackend *backend = meta_get_backend ();
   MetaEgl *egl = meta_backend_get_egl (backend);
   char **missing_extensions;
   EGLint num_devices;
   EGLDeviceEXT *devices;
+  const char *kms_file_path;
   EGLDeviceEXT device;
   EGLint i;
 
@@ -2020,6 +2026,8 @@ find_egl_device (MetaRendererNative *renderer_native,
       return EGL_NO_DEVICE_EXT;
     }
 
+  kms_file_path = meta_monitor_manager_kms_get_file_path (monitor_manager_kms);
+
   device = EGL_NO_DEVICE_EXT;
   for (i = 0; i < num_devices; i++)
     {
@@ -2031,7 +2039,7 @@ find_egl_device (MetaRendererNative *renderer_native,
       if (!egl_device_drm_path)
         continue;
 
-      if (g_str_equal (egl_device_drm_path, renderer_native->kms_file_path))
+      if (g_str_equal (egl_device_drm_path, kms_file_path))
         {
           device = devices[i];
           break;
@@ -2058,8 +2066,11 @@ get_egl_device_display (MetaRendererNative *renderer_native,
 {
   MetaBackend *backend = meta_get_backend ();
   MetaEgl *egl = meta_backend_get_egl (backend);
+  MetaMonitorManagerKms *monitor_manager_kms =
+    renderer_native->monitor_manager_kms;
+  int kms_fd = meta_monitor_manager_kms_get_fd (monitor_manager_kms);
   EGLint platform_attribs[] = {
-    EGL_DRM_MASTER_FD_EXT, renderer_native->kms_fd,
+    EGL_DRM_MASTER_FD_EXT, kms_fd,
     EGL_NONE
   };
 
@@ -2204,34 +2215,25 @@ meta_renderer_native_class_init (MetaRendererNativeClass *klass)
   renderer_class->create_cogl_renderer = meta_renderer_native_create_cogl_renderer;
   renderer_class->create_view = meta_renderer_native_create_view;
 
-  g_object_class_install_property (object_class,
-                                   PROP_KMS_FD,
-                                   g_param_spec_int ("kms-fd",
-                                                     "KMS fd",
-                                                     "The KMS file descriptor",
-                                                     0, G_MAXINT, 0,
-                                                     G_PARAM_READWRITE |
-                                                     G_PARAM_CONSTRUCT_ONLY));
-  g_object_class_install_property (object_class,
-                                   PROP_KMS_FILE_PATH,
-                                   g_param_spec_string ("kms-file-path",
-                                                        "KMS file path",
-                                                        "The KMS file path",
-                                                        NULL,
-                                                        G_PARAM_READWRITE |
-                                                        G_PARAM_CONSTRUCT_ONLY));
+  obj_props[PROP_MONITOR_MANAGER] =
+    g_param_spec_object ("monitor-manager",
+                         "monitor-manager",
+                         "MetaMonitorManagerKms",
+                         META_TYPE_MONITOR_MANAGER_KMS,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+  g_object_class_install_properties (object_class, PROP_LAST, obj_props);
 }
 
 MetaRendererNative *
-meta_renderer_native_new (int         kms_fd,
-                          const char *kms_file_path,
-                          GError    **error)
+meta_renderer_native_new (MetaMonitorManagerKms *monitor_manager_kms,
+                          GError               **error)
 {
   MetaRendererNative *renderer_native;
 
   renderer_native = g_object_new (META_TYPE_RENDERER_NATIVE,
-                                  "kms-fd", kms_fd,
-                                  "kms-file-path", kms_file_path,
+                                  "monitor-manager", monitor_manager_kms,
                                   NULL);
   if (!g_initable_init (G_INITABLE (renderer_native), NULL, error))
     {
diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h
index 24cfdd3..ef774cc 100644
--- a/src/backends/native/meta-renderer-native.h
+++ b/src/backends/native/meta-renderer-native.h
@@ -29,6 +29,7 @@
 #include <xf86drmMode.h>
 
 #include "backends/meta-renderer.h"
+#include "backends/native/meta-monitor-manager-kms.h"
 
 #define META_TYPE_RENDERER_NATIVE (meta_renderer_native_get_type ())
 G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native,
@@ -43,16 +44,13 @@ typedef enum _MetaRendererNativeMode
 #endif
 } MetaRendererNativeMode;
 
-MetaRendererNative *meta_renderer_native_new (int         kms_fd,
-                                              const char *kms_file_path,
-                                              GError    **error);
+MetaRendererNative * meta_renderer_native_new (MetaMonitorManagerKms *monitor_manager_kms,
+                                               GError               **error);
 
 MetaRendererNativeMode meta_renderer_native_get_mode (MetaRendererNative *renderer_native);
 
 struct gbm_device * meta_renderer_native_get_gbm (MetaRendererNative *renderer_native);
 
-int meta_renderer_native_get_kms_fd (MetaRendererNative *renderer_native);
-
 void meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native);
 
 gboolean meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
diff --git a/src/backends/x11/cm/meta-backend-x11-cm.c b/src/backends/x11/cm/meta-backend-x11-cm.c
index 06825f3..1cb914d 100644
--- a/src/backends/x11/cm/meta-backend-x11-cm.c
+++ b/src/backends/x11/cm/meta-backend-x11-cm.c
@@ -99,7 +99,8 @@ meta_backend_x11_cm_create_renderer (MetaBackend *backend,
 }
 
 static MetaMonitorManager *
-meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend)
+meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend,
+                                            GError     **error)
 {
   return g_object_new (META_TYPE_MONITOR_MANAGER_XRANDR, NULL);
 }
diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c 
b/src/backends/x11/nested/meta-backend-x11-nested.c
index 644c270..900c97f 100644
--- a/src/backends/x11/nested/meta-backend-x11-nested.c
+++ b/src/backends/x11/nested/meta-backend-x11-nested.c
@@ -39,7 +39,8 @@ meta_backend_x11_nested_create_renderer (MetaBackend *backend,
 }
 
 static MetaMonitorManager *
-meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend)
+meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend,
+                                                GError     **error)
 {
   return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL);
 }
diff --git a/src/tests/meta-backend-test.c b/src/tests/meta-backend-test.c
index 4abe0b7..ef597ad 100644
--- a/src/tests/meta-backend-test.c
+++ b/src/tests/meta-backend-test.c
@@ -36,7 +36,8 @@ meta_backend_test_init (MetaBackendTest *backend_test)
 }
 
 static MetaMonitorManager *
-meta_backend_test_create_monitor_manager (MetaBackend *backend)
+meta_backend_test_create_monitor_manager (MetaBackend *backend,
+                                          GError     **error)
 {
   return g_object_new (META_TYPE_MONITOR_MANAGER_TEST, NULL);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]