[mutter] kms: Add way to run without mode setting



commit ee4e78b1002d30654ad439b0d227cca39edceaff
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Tue Jan 19 14:54:45 2021 +0100

    kms: Add way to run without mode setting
    
    Currently our only entry point for DRM devices is MetaKms*, but in order
    to run without being DRM master, we cannot use /dev/dri/card*, nor can
    we be either of the existing MetaKmsImplDevice implementation (legacy
    KMS, and atomic KMS), as they both depend on being DRM master.
    
    Thus to handle running without being DRM master (i.e. headless), add a
    "dummy" MetaKmsImplDevice implementation, that doesn't do any mode
    setting at all, and that switches to operate on the render node, instead
    of the card node itself.
    
    This means we still use the same GBM code paths as the regular native
    backend paths, except we never make use of any CRTC backed onscreen
    framebuffers.
    
    Eventually, this "dummy" MetaKmsImplDevice will be replaced separating
    "KMS" device objects from "render" device objects, but that will require
    more significant changes. It will, however, be necessary for e.g. going
    from being headless, only having access to a render node, to turning
    into a real session, with a seat, being DRM master, and having access to
    a card node.
    
    This is currently not hooked up, but will be in a later commit.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1698>

 src/backends/native/meta-backend-native.c        |   4 +-
 src/backends/native/meta-kms-device.c            | 119 +++++++++++++++++++----
 src/backends/native/meta-kms-impl-device-dummy.c |  69 +++++++++++++
 src/backends/native/meta-kms-impl-device-dummy.h |  30 ++++++
 src/backends/native/meta-kms-impl-device.c       |  18 ++++
 src/backends/native/meta-kms-types.h             |   1 +
 src/backends/native/meta-kms.c                   |  19 +++-
 src/backends/native/meta-kms.h                   |  11 ++-
 src/meson.build                                  |   3 +
 9 files changed, 248 insertions(+), 26 deletions(-)
---
diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c
index 8f916642e0..eb43a54ec5 100644
--- a/src/backends/native/meta-backend-native.c
+++ b/src/backends/native/meta-backend-native.c
@@ -531,7 +531,9 @@ meta_backend_native_initable_init (GInitable     *initable,
 
   native->udev = meta_udev_new (native);
 
-  native->kms = meta_kms_new (META_BACKEND (native), error);
+  native->kms = meta_kms_new (META_BACKEND (native),
+                              META_KMS_FLAG_NONE,
+                              error);
   if (!native->kms)
     return FALSE;
 
diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c
index 9084d248fe..c388096d59 100644
--- a/src/backends/native/meta-kms-device.c
+++ b/src/backends/native/meta-kms-device.c
@@ -23,10 +23,14 @@
 #include "backends/native/meta-kms-device-private.h"
 #include "backends/native/meta-kms-device.h"
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <xf86drm.h>
 
 #include "backends/native/meta-backend-native.h"
 #include "backends/native/meta-kms-impl-device-atomic.h"
+#include "backends/native/meta-kms-impl-device-dummy.h"
 #include "backends/native/meta-kms-impl-device-simple.h"
 #include "backends/native/meta-kms-impl-device.h"
 #include "backends/native/meta-kms-impl.h"
@@ -227,6 +231,7 @@ typedef struct _CreateImplDeviceData
   MetaKmsDevice *device;
   int fd;
   const char *path;
+  MetaKmsDeviceFlag flags;
 
   MetaKmsImplDevice *out_impl_device;
   GList *out_crtcs;
@@ -236,6 +241,7 @@ typedef struct _CreateImplDeviceData
   GList *out_fallback_modes;
   char *out_driver_name;
   char *out_driver_description;
+  char *out_path;
 } CreateImplDeviceData;
 
 static gboolean
@@ -273,17 +279,21 @@ get_driver_info (int    fd,
 }
 
 static MetaKmsImplDevice *
-meta_create_kms_impl_device (MetaKmsDevice  *device,
-                             MetaKmsImpl    *impl,
-                             int             fd,
-                             const char     *path,
-                             GError        **error)
+meta_create_kms_impl_device (MetaKmsDevice      *device,
+                             MetaKmsImpl        *impl,
+                             int                 fd,
+                             const char         *path,
+                             MetaKmsDeviceFlag   flags,
+                             GError            **error)
 {
   GType impl_device_type;
   gboolean supports_atomic_mode_setting;
   g_autofree char *driver_name = NULL;
   g_autofree char *driver_description = NULL;
   const char *atomic_kms_enable_env;
+  int impl_fd;
+  g_autofree char *impl_path = NULL;
+  MetaKmsImplDevice *impl_device;
 
   meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl));
 
@@ -294,7 +304,36 @@ meta_create_kms_impl_device (MetaKmsDevice  *device,
     }
 
   atomic_kms_enable_env = getenv ("MUTTER_DEBUG_ENABLE_ATOMIC_KMS");
-  if (atomic_kms_enable_env)
+
+  if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)
+    {
+      g_autofree char *render_node_path = NULL;
+
+      render_node_path = drmGetRenderDeviceNameFromFd (fd);
+      if (!render_node_path)
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "Couldn't find render node device for '%s' (%s)",
+                       path, driver_name);
+          return NULL;
+        }
+
+      impl_fd = open (render_node_path, O_RDWR | O_CLOEXEC, 0);
+      if (impl_fd == -1)
+        {
+          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+                       "Failed to open render node '%s': %s",
+                       render_node_path, g_strerror (errno));
+          return NULL;
+        }
+
+      g_message ("Adding device '%s' (from '%s', %s) using no mode setting.",
+                 render_node_path, path, driver_name);
+
+      impl_path = g_steal_pointer (&render_node_path);
+      impl_device_type = META_TYPE_KMS_IMPL_DEVICE_DUMMY;
+    }
+  else if (atomic_kms_enable_env)
     {
       if (g_strcmp0 (atomic_kms_enable_env, "1") == 0)
         {
@@ -316,6 +355,9 @@ meta_create_kms_impl_device (MetaKmsDevice  *device,
                    atomic_kms_enable_env);
         }
 
+      impl_fd = dup (fd);
+      impl_path = g_strdup (path);
+
       g_message ("Mode setting implementation for '%s' (%s) forced (%s).",
                  path, driver_name,
                  impl_device_type == META_TYPE_KMS_IMPL_DEVICE_ATOMIC ?
@@ -326,6 +368,8 @@ meta_create_kms_impl_device (MetaKmsDevice  *device,
       g_message ("Adding device '%s' (%s) using non-atomic mode setting"
                  " (using atomic mode setting not allowed).",
                  path, driver_name);
+      impl_fd = dup (fd);
+      impl_path = g_strdup (path);
       impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE;
     }
   else
@@ -350,16 +394,29 @@ meta_create_kms_impl_device (MetaKmsDevice  *device,
                      path, driver_name);
           impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE;
         }
+
+      impl_fd = dup (fd);
+      impl_path = g_strdup (path);
+    }
+
+  impl_device = g_initable_new (impl_device_type, NULL, error,
+                                "device", device,
+                                "impl", impl,
+                                "fd", impl_fd,
+                                "path", impl_path,
+                                "flags", flags,
+                                "driver-name", driver_name,
+                                "driver-description", driver_description,
+                                NULL);
+  if (!impl_device)
+    {
+      close (impl_fd);
+      return NULL;
     }
 
-  return g_initable_new (impl_device_type, NULL, error,
-                         "device", device,
-                         "impl", impl,
-                         "fd", fd,
-                         "path", path,
-                         "driver-name", driver_name,
-                         "driver-description", driver_description,
-                         NULL);
+  close (fd);
+
+  return impl_device;
 }
 
 static gpointer
@@ -374,6 +431,7 @@ create_impl_device_in_impl (MetaKmsImpl  *impl,
                                              impl,
                                              data->fd,
                                              data->path,
+                                             data->flags,
                                              error);
   if (!impl_device)
     return FALSE;
@@ -391,6 +449,7 @@ create_impl_device_in_impl (MetaKmsImpl  *impl,
     g_strdup (meta_kms_impl_device_get_driver_name (impl_device));
   data->out_driver_description =
     g_strdup (meta_kms_impl_device_get_driver_description (impl_device));
+  data->out_path = g_strdup (meta_kms_impl_device_get_path (impl_device));
 
   return GINT_TO_POINTER (TRUE);
 }
@@ -408,9 +467,22 @@ meta_kms_device_new (MetaKms            *kms,
   CreateImplDeviceData data;
   int fd;
 
-  fd = meta_launcher_open_restricted (launcher, path, error);
-  if (fd == -1)
-    return NULL;
+  if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)
+    {
+      fd = open (path, O_RDWR | O_CLOEXEC, 0);
+      if (fd == -1)
+        {
+          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+                       "Failed to open DRM device: %s", g_strerror (errno));
+          return NULL;
+        }
+    }
+  else
+    {
+      fd = meta_launcher_open_restricted (launcher, path, error);
+      if (fd == -1)
+        return NULL;
+    }
 
   device = g_object_new (META_TYPE_KMS_DEVICE, NULL);
   device->kms = kms;
@@ -419,11 +491,15 @@ meta_kms_device_new (MetaKms            *kms,
     .device = device,
     .fd = fd,
     .path = path,
+    .flags = flags,
   };
   if (!meta_kms_run_impl_task_sync (kms, create_impl_device_in_impl, &data,
                                     error))
     {
-      meta_launcher_close_restricted (launcher, fd);
+      if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)
+        close (fd);
+      else
+        meta_launcher_close_restricted (launcher, fd);
       g_object_unref (device);
       return NULL;
     }
@@ -438,6 +514,8 @@ meta_kms_device_new (MetaKms            *kms,
   device->fallback_modes = data.out_fallback_modes;
   device->driver_name = data.out_driver_name;
   device->driver_description = data.out_driver_description;
+  free (device->path);
+  device->path = data.out_path;
 
   return device;
 }
@@ -495,7 +573,10 @@ meta_kms_device_finalize (GObject *object)
         }
       else
         {
-          meta_launcher_close_restricted (launcher, data.out_fd);
+          if (device->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING)
+            close (data.out_fd);
+          else
+            meta_launcher_close_restricted (launcher, data.out_fd);
         }
     }
   G_OBJECT_CLASS (meta_kms_device_parent_class)->finalize (object);
diff --git a/src/backends/native/meta-kms-impl-device-dummy.c 
b/src/backends/native/meta-kms-impl-device-dummy.c
new file mode 100644
index 0000000000..c1a0a44307
--- /dev/null
+++ b/src/backends/native/meta-kms-impl-device-dummy.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "backends/native/meta-kms-impl-device-dummy.h"
+
+struct _MetaKmsImplDeviceDummy
+{
+  MetaKmsImplDevice parent;
+};
+
+static void
+initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy,
+                         META_TYPE_KMS_IMPL_DEVICE,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                initable_iface_init))
+
+static void
+meta_kms_impl_device_dummy_discard_pending_page_flips (MetaKmsImplDevice *impl)
+{
+}
+
+static void
+meta_kms_impl_device_dummy_init (MetaKmsImplDeviceDummy *impl_device_dummy)
+{
+}
+
+static gboolean
+meta_kms_impl_device_dummy_initable_init (GInitable     *initable,
+                                          GCancellable  *cancellable,
+                                          GError       **error)
+{
+  return TRUE;
+}
+
+static void
+initable_iface_init (GInitableIface *iface)
+{
+  iface->init = meta_kms_impl_device_dummy_initable_init;
+}
+
+static void
+meta_kms_impl_device_dummy_class_init (MetaKmsImplDeviceDummyClass *klass)
+{
+  MetaKmsImplDeviceClass *impl_device_class =
+    META_KMS_IMPL_DEVICE_CLASS (klass);
+
+  impl_device_class->discard_pending_page_flips =
+    meta_kms_impl_device_dummy_discard_pending_page_flips;
+}
diff --git a/src/backends/native/meta-kms-impl-device-dummy.h 
b/src/backends/native/meta-kms-impl-device-dummy.h
new file mode 100644
index 0000000000..9576939ad8
--- /dev/null
+++ b/src/backends/native/meta-kms-impl-device-dummy.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_KMS_IMPL_DEVICE_DUMMY_H
+#define META_KMS_IMPL_DEVICE_DUMMY_H
+
+#include "backends/native/meta-kms-impl-device.h"
+
+#define META_TYPE_KMS_IMPL_DEVICE_DUMMY (meta_kms_impl_device_dummy_get_type ())
+G_DECLARE_FINAL_TYPE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy,
+                      META, KMS_IMPL_DEVICE_DUMMY,
+                      MetaKmsImplDevice)
+
+#endif /* META_KMS_IMPL_DEVICE_DUMMY_H */
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index f2a000fd1a..d0247ef71f 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -37,6 +37,7 @@
 #include "backends/native/meta-kms-update.h"
 
 #include "meta-default-modes.h"
+#include "meta-private-enum-types.h"
 
 enum
 {
@@ -46,6 +47,7 @@ enum
   PROP_IMPL,
   PROP_FD,
   PROP_PATH,
+  PROP_FLAGS,
   PROP_DRIVER_NAME,
   PROP_DRIVER_DESCRIPTION,
 
@@ -62,6 +64,7 @@ typedef struct _MetaKmsImplDevicePrivate
   int fd;
   GSource *fd_source;
   char *path;
+  MetaKmsDeviceFlag flags;
 
   char *driver_name;
   char *driver_description;
@@ -712,6 +715,9 @@ meta_kms_impl_device_get_property (GObject    *object,
     case PROP_PATH:
       g_value_set_string (value, priv->path);
       break;
+    case PROP_FLAGS:
+      g_value_set_flags (value, priv->flags);
+      break;
     case PROP_DRIVER_NAME:
       g_value_set_string (value, priv->driver_name);
       break;
@@ -748,6 +754,9 @@ meta_kms_impl_device_set_property (GObject      *object,
     case PROP_PATH:
       priv->path = g_value_dup_string (value);
       break;
+    case PROP_FLAGS:
+      priv->flags = g_value_get_flags (value);
+      break;
     case PROP_DRIVER_NAME:
       priv->driver_name = g_value_dup_string (value);
       break;
@@ -873,6 +882,15 @@ meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass)
                          G_PARAM_READWRITE |
                          G_PARAM_CONSTRUCT_ONLY |
                          G_PARAM_STATIC_STRINGS);
+  obj_props[PROP_FLAGS] =
+    g_param_spec_flags ("flags",
+                        "flags",
+                        "KMS impl device flags",
+                        META_TYPE_KMS_DEVICE_FLAG,
+                        META_KMS_DEVICE_FLAG_NONE,
+                        G_PARAM_READWRITE |
+                        G_PARAM_CONSTRUCT_ONLY |
+                        G_PARAM_STATIC_STRINGS);
   obj_props[PROP_DRIVER_NAME] =
     g_param_spec_string ("driver-name",
                          "driver-name",
diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h
index cf1adc44ef..01db55a402 100644
--- a/src/backends/native/meta-kms-types.h
+++ b/src/backends/native/meta-kms-types.h
@@ -61,6 +61,7 @@ typedef enum _MetaKmsDeviceFlag
   META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1,
   META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS = 1 << 2,
   META_KMS_DEVICE_FLAG_PREFERRED_PRIMARY = 1 << 3,
+  META_KMS_DEVICE_FLAG_NO_MODE_SETTING = 1 << 4,
 } MetaKmsDeviceFlag;
 
 typedef enum _MetaKmsPlaneType MetaKmsPlaneType;
diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c
index ee77975bd4..6514f89f6e 100644
--- a/src/backends/native/meta-kms.c
+++ b/src/backends/native/meta-kms.c
@@ -158,6 +158,8 @@ struct _MetaKms
 {
   GObject parent;
 
+  MetaKmsFlags flags;
+
   MetaBackend *backend;
 
   gulong hotplug_handler_id;
@@ -614,6 +616,9 @@ meta_kms_create_device (MetaKms            *kms,
 {
   MetaKmsDevice *device;
 
+  if (kms->flags & META_KMS_FLAG_NO_MODE_SETTING)
+    flags |= META_KMS_DEVICE_FLAG_NO_MODE_SETTING;
+
   device = meta_kms_device_new (kms, path, flags, error);
   if (!device)
     return NULL;
@@ -624,14 +629,16 @@ meta_kms_create_device (MetaKms            *kms,
 }
 
 MetaKms *
-meta_kms_new (MetaBackend  *backend,
-              GError      **error)
+meta_kms_new (MetaBackend   *backend,
+              MetaKmsFlags   flags,
+              GError       **error)
 {
   MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend);
   MetaUdev *udev = meta_backend_native_get_udev (backend_native);
   MetaKms *kms;
 
   kms = g_object_new (META_TYPE_KMS, NULL);
+  kms->flags = flags;
   kms->backend = backend;
   kms->impl = meta_kms_impl_new (kms);
   if (!kms->impl)
@@ -640,8 +647,12 @@ meta_kms_new (MetaBackend  *backend,
       return NULL;
     }
 
-  kms->hotplug_handler_id =
-    g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms);
+  if (!(flags & META_KMS_FLAG_NO_MODE_SETTING))
+    {
+      kms->hotplug_handler_id =
+        g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms);
+    }
+
   kms->removed_handler_id =
     g_signal_connect (udev, "device-removed",
                       G_CALLBACK (on_udev_device_removed), kms);
diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h
index 7bbd78e0c5..27b4e3537e 100644
--- a/src/backends/native/meta-kms.h
+++ b/src/backends/native/meta-kms.h
@@ -25,6 +25,12 @@
 #include "backends/meta-backend-private.h"
 #include "backends/native/meta-kms-types.h"
 
+typedef enum _MetaKmsFlags
+{
+  META_KMS_FLAG_NONE = 0,
+  META_KMS_FLAG_NO_MODE_SETTING = 1 << 0,
+} MetaKmsFlags;
+
 typedef enum _MetaKmsUpdateFlag
 {
   META_KMS_UPDATE_FLAG_NONE = 0,
@@ -57,7 +63,8 @@ MetaKmsDevice * meta_kms_create_device (MetaKms            *kms,
                                         MetaKmsDeviceFlag   flags,
                                         GError            **error);
 
-MetaKms * meta_kms_new (MetaBackend  *backend,
-                        GError      **error);
+MetaKms * meta_kms_new (MetaBackend   *backend,
+                        MetaKmsFlags   flags,
+                        GError       **error);
 
 #endif /* META_KMS_H */
diff --git a/src/meson.build b/src/meson.build
index 196abf71f4..6f52ab7141 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -689,6 +689,8 @@ if have_native_backend
     'backends/native/meta-kms-device.h',
     'backends/native/meta-kms-impl-device-atomic.c',
     'backends/native/meta-kms-impl-device-atomic.h',
+    'backends/native/meta-kms-impl-device-dummy.c',
+    'backends/native/meta-kms-impl-device-dummy.h',
     'backends/native/meta-kms-impl-device-simple.c',
     'backends/native/meta-kms-impl-device-simple.h',
     'backends/native/meta-kms-impl-device.c',
@@ -755,6 +757,7 @@ endif
 if have_native_backend
   mutter_private_enum_sources += [
     'backends/native/meta-backend-native-types.h',
+    'backends/native/meta-kms-types.h',
   ]
 endif
 


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