[mutter] Introduce MetaRenderDevice{Gbm,EglStream,Surfaceless}



commit 2047d2d4e9ab38586f6c3cbb7508b4837941bd0e
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Mon May 3 19:23:52 2021 +0200

    Introduce MetaRenderDevice{Gbm,EglStream,Surfaceless}
    
    The purpose of MetaRenderDevice is to contain the logics related to a
    render device; i.e. e.g. a gbm_device, or an EGLDevice. It's meant to
    help abstract away unrelated details from where it's eventually used,
    which will be by MetaRendererNative and the MetaOnscreenNative
    instances.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1854>

 .../native/meta-render-device-egl-stream.c         | 286 +++++++++++++++++
 .../native/meta-render-device-egl-stream.h         |  35 +++
 src/backends/native/meta-render-device-gbm.c       | 155 ++++++++++
 src/backends/native/meta-render-device-gbm.h       |  35 +++
 src/backends/native/meta-render-device-private.h   |  39 +++
 .../native/meta-render-device-surfaceless.c        |  92 ++++++
 .../native/meta-render-device-surfaceless.h        |  34 +++
 src/backends/native/meta-render-device.c           | 340 +++++++++++++++++++++
 src/backends/native/meta-render-device.h           |  43 +++
 src/meson.build                                    |  14 +
 10 files changed, 1073 insertions(+)
---
diff --git a/src/backends/native/meta-render-device-egl-stream.c 
b/src/backends/native/meta-render-device-egl-stream.c
new file mode 100644
index 0000000000..fa287a66d5
--- /dev/null
+++ b/src/backends/native/meta-render-device-egl-stream.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2016-2021 Red Hat Inc.
+ *
+ * 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-render-device-egl-stream.h"
+
+#include "backends/meta-backend-private.h"
+
+struct _MetaRenderDeviceEglStream
+{
+  MetaRenderDevice parent;
+
+  EGLDeviceEXT egl_device;
+};
+
+static GInitableIface *initable_parent_iface;
+
+static void
+initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaRenderDeviceEglStream, meta_render_device_egl_stream,
+                         META_TYPE_RENDER_DEVICE,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                initable_iface_init))
+
+static EGLDisplay
+get_egl_device_display (MetaRenderDevice  *render_device,
+                        EGLDeviceEXT       egl_device,
+                        GError           **error)
+{
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  MetaDeviceFile *device_file =
+    meta_render_device_get_device_file (render_device);
+  int kms_fd = meta_device_file_get_fd (device_file);
+  EGLint platform_attribs[] = {
+    EGL_DRM_MASTER_FD_EXT, kms_fd,
+    EGL_NONE
+  };
+
+  return meta_egl_get_platform_display (egl, EGL_PLATFORM_DEVICE_EXT,
+                                        (void *) egl_device,
+                                        platform_attribs,
+                                        error);
+}
+
+static int
+count_mode_setting_devices (MetaBackend *backend)
+{
+  return g_list_length (meta_backend_get_gpus (backend));
+}
+
+static const char *
+get_drm_device_file (MetaEgl     *egl,
+                     EGLDeviceEXT device,
+                     GError     **error)
+{
+  if (!meta_egl_egl_device_has_extensions (egl, device,
+                                           NULL,
+                                           "EGL_EXT_device_drm",
+                                           NULL))
+    {
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Missing required EGLDevice extension EGL_EXT_device_drm");
+      return NULL;
+    }
+
+  return meta_egl_query_device_string (egl, device,
+                                       EGL_DRM_DEVICE_FILE_EXT,
+                                       error);
+}
+
+static EGLDeviceEXT
+find_egl_device (MetaRenderDevice  *render_device,
+                 GError           **error)
+{
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  g_autofree const char **missing_extensions = NULL;
+  MetaDeviceFile *device_file =
+    meta_render_device_get_device_file (render_device);
+  EGLint num_devices;
+  g_autofree EGLDeviceEXT *devices = NULL;
+  const char *device_file_path;
+  EGLDeviceEXT device;
+  EGLint i;
+
+  if (!meta_egl_has_extensions (egl,
+                                EGL_NO_DISPLAY,
+                                &missing_extensions,
+                                "EGL_EXT_device_base",
+                                NULL))
+    {
+      g_autofree char *missing_extensions_str = NULL;
+
+      missing_extensions_str = g_strjoinv (", ", (char **) missing_extensions);
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Missing EGL extensions required for EGLDevice renderer: %s",
+                   missing_extensions_str);
+      return EGL_NO_DEVICE_EXT;
+    }
+
+  if (!meta_egl_query_devices (egl, 0, NULL, &num_devices, error))
+    return EGL_NO_DEVICE_EXT;
+
+  devices = g_new0 (EGLDeviceEXT, num_devices);
+  if (!meta_egl_query_devices (egl, num_devices, devices, &num_devices,
+                               error))
+    return EGL_NO_DEVICE_EXT;
+
+  device_file_path = meta_device_file_get_path (device_file);
+
+  device = EGL_NO_DEVICE_EXT;
+  for (i = 0; i < num_devices; i++)
+    {
+      const char *egl_device_drm_path;
+
+      g_clear_error (error);
+
+      egl_device_drm_path = get_drm_device_file (egl, devices[i], error);
+      if (!egl_device_drm_path)
+        continue;
+
+      if (g_str_equal (egl_device_drm_path, device_file_path))
+        {
+          device = devices[i];
+          break;
+        }
+    }
+
+  if (device == EGL_NO_DEVICE_EXT)
+    {
+      if (!*error)
+        g_set_error (error, G_IO_ERROR,
+                     G_IO_ERROR_FAILED,
+                     "Failed to find matching EGLDeviceEXT");
+      return EGL_NO_DEVICE_EXT;
+    }
+
+  return device;
+}
+
+static gboolean
+meta_render_device_egl_stream_initable_init (GInitable     *initable,
+                                             GCancellable  *cancellable,
+                                             GError       **error)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (initable);
+  MetaRenderDeviceEglStream *render_device_egl_stream =
+    META_RENDER_DEVICE_EGL_STREAM (initable);
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  EGLDeviceEXT egl_device;
+  EGLDisplay egl_display;
+  g_autofree const char **missing_extensions = NULL;
+
+  if (count_mode_setting_devices (backend) != 1)
+    {
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "EGLDevice currently only works with single GPU systems");
+      return FALSE;
+    }
+
+  egl_device = find_egl_device (render_device, error);
+  if (egl_device == EGL_NO_DEVICE_EXT)
+    return FALSE;
+
+  render_device_egl_stream->egl_device = egl_device;
+
+  if (!initable_parent_iface->init (initable, cancellable, error))
+    return FALSE;
+
+  egl_display = meta_render_device_get_egl_display (render_device);
+  if (egl_display == EGL_NO_DISPLAY)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "EGLStream render device requires an EGL display");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+  initable_parent_iface = g_type_interface_peek_parent (initable_iface);
+
+  initable_iface->init = meta_render_device_egl_stream_initable_init;
+}
+
+static EGLDisplay
+meta_render_device_egl_stream_create_egl_display (MetaRenderDevice  *render_device,
+                                                  GError           **error)
+{
+  MetaRenderDeviceEglStream *render_device_egl_stream =
+    META_RENDER_DEVICE_EGL_STREAM (render_device);
+  EGLDeviceEXT egl_device = render_device_egl_stream->egl_device;
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  EGLDisplay egl_display;
+  g_autofree const char **missing_extensions = NULL;
+
+  egl_display = get_egl_device_display (render_device, egl_device, error);
+  if (egl_display == EGL_NO_DISPLAY)
+    return EGL_NO_DISPLAY;
+
+  if (!meta_egl_initialize (egl, egl_display, error))
+    {
+      meta_egl_terminate (egl, egl_display, NULL);
+      return EGL_NO_DISPLAY;
+    }
+
+  if (!meta_egl_has_extensions (egl,
+                                egl_display,
+                                &missing_extensions,
+                                "EGL_NV_output_drm_flip_event",
+                                "EGL_EXT_output_base",
+                                "EGL_EXT_output_drm",
+                                "EGL_KHR_stream",
+                                "EGL_KHR_stream_producer_eglsurface",
+                                "EGL_EXT_stream_consumer_egloutput",
+                                "EGL_EXT_stream_acquire_mode",
+                                NULL))
+    {
+      g_autofree char *missing_extensions_str = NULL;
+
+      meta_egl_terminate (egl, egl_display, NULL);
+
+      missing_extensions_str = g_strjoinv (", ", (char **) missing_extensions);
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Missing EGL extensions required for EGLDevice renderer: %s",
+                   missing_extensions_str);
+      meta_egl_terminate (egl, egl_display, NULL);
+      return EGL_NO_DISPLAY;
+    }
+
+  return egl_display;
+}
+
+static void
+meta_render_device_egl_stream_class_init (MetaRenderDeviceEglStreamClass *klass)
+{
+  MetaRenderDeviceClass *render_device_class = META_RENDER_DEVICE_CLASS (klass);
+
+  render_device_class->create_egl_display =
+    meta_render_device_egl_stream_create_egl_display;
+}
+
+static void
+meta_render_device_egl_stream_init (MetaRenderDeviceEglStream *render_device_egl_stream)
+{
+}
+
+MetaRenderDeviceEglStream *
+meta_render_device_egl_stream_new (MetaBackend     *backend,
+                                   MetaDeviceFile  *device_file,
+                                   GError         **error)
+{
+  return g_initable_new (META_TYPE_RENDER_DEVICE_EGL_STREAM,
+                         NULL, error,
+                         "backend", backend,
+                         "device-file", device_file,
+                         NULL);
+}
diff --git a/src/backends/native/meta-render-device-egl-stream.h 
b/src/backends/native/meta-render-device-egl-stream.h
new file mode 100644
index 0000000000..b4b66b8b17
--- /dev/null
+++ b/src/backends/native/meta-render-device-egl-stream.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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_RENDER_DEVICE_EGL_STREAM_H
+#define META_RENDER_DEVICE_EGL_STREAM_H
+
+#include "backends/native/meta-render-device-private.h"
+
+#define META_TYPE_RENDER_DEVICE_EGL_STREAM (meta_render_device_egl_stream_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRenderDeviceEglStream, meta_render_device_egl_stream,
+                      META, RENDER_DEVICE_EGL_STREAM,
+                      MetaRenderDevice)
+
+MetaRenderDeviceEglStream * meta_render_device_egl_stream_new (MetaBackend     *backend,
+                                                               MetaDeviceFile  *device_file,
+                                                               GError         **error);
+
+#endif /* META_RENDER_DEVICE_EGL_STREAM_H */
diff --git a/src/backends/native/meta-render-device-gbm.c b/src/backends/native/meta-render-device-gbm.c
new file mode 100644
index 0000000000..5dc99d379e
--- /dev/null
+++ b/src/backends/native/meta-render-device-gbm.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2016-2021 Red Hat Inc.
+ * Copyright (c) 2018-2019 DisplayLink (UK) Ltd.
+ *
+ * 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-render-device-gbm.h"
+
+#include <gbm.h>
+
+#include "backends/meta-backend-private.h"
+
+struct _MetaRenderDeviceGbm
+{
+  MetaRenderDevice parent;
+
+  struct gbm_device *gbm_device;
+};
+
+static GInitableIface *initable_parent_iface;
+
+static void
+initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (MetaRenderDeviceGbm, meta_render_device_gbm,
+                         META_TYPE_RENDER_DEVICE,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                initable_iface_init))
+
+static gboolean
+meta_render_device_gbm_initable_init (GInitable     *initable,
+                                      GCancellable  *cancellable,
+                                      GError       **error)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (initable);
+  MetaRenderDeviceGbm *render_device_gbm = META_RENDER_DEVICE_GBM (initable);
+  MetaDeviceFile *device_file =
+    meta_render_device_get_device_file (render_device);
+  struct gbm_device *gbm_device;
+
+  gbm_device = gbm_create_device (meta_device_file_get_fd (device_file));
+  if (!gbm_device)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Failed to create gbm device: %s", g_strerror (errno));
+      return FALSE;
+    }
+
+  render_device_gbm->gbm_device = gbm_device;
+
+  return initable_parent_iface->init (initable, cancellable, error);
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+  initable_parent_iface = g_type_interface_peek_parent (initable_iface);
+
+  initable_iface->init = meta_render_device_gbm_initable_init;
+}
+
+static EGLDisplay
+meta_render_device_gbm_create_egl_display (MetaRenderDevice  *render_device,
+                                           GError           **error)
+{
+  MetaRenderDeviceGbm *render_device_gbm =
+    META_RENDER_DEVICE_GBM (render_device);
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  EGLDisplay egl_display;
+
+  if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
+                                "EGL_MESA_platform_gbm",
+                                NULL) &&
+      !meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
+                                "EGL_KHR_platform_gbm",
+                                NULL))
+    {
+      g_set_error (error, G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Missing extension for GBM renderer: EGL_KHR_platform_gbm");
+      return EGL_NO_DISPLAY;
+    }
+
+  egl_display = meta_egl_get_platform_display (egl,
+                                               EGL_PLATFORM_GBM_KHR,
+                                               render_device_gbm->gbm_device,
+                                               NULL, error);
+  if (egl_display == EGL_NO_DISPLAY)
+    return EGL_NO_DISPLAY;
+
+  if (!meta_egl_initialize (egl, egl_display, error))
+    {
+      meta_egl_terminate (egl, egl_display, NULL);
+      return EGL_NO_DISPLAY;
+    }
+
+  return egl_display;
+}
+
+static void
+meta_render_device_gbm_finalize (GObject *object)
+{
+  MetaRenderDeviceGbm *render_device_gbm = META_RENDER_DEVICE_GBM (object);
+
+  g_clear_pointer (&render_device_gbm->gbm_device, gbm_device_destroy);
+
+  G_OBJECT_CLASS (meta_render_device_gbm_parent_class)->finalize (object);
+}
+
+static void
+meta_render_device_gbm_class_init (MetaRenderDeviceGbmClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  MetaRenderDeviceClass *render_device_class = META_RENDER_DEVICE_CLASS (klass);
+
+  object_class->finalize = meta_render_device_gbm_finalize;
+
+  render_device_class->create_egl_display =
+    meta_render_device_gbm_create_egl_display;
+}
+
+static void
+meta_render_device_gbm_init (MetaRenderDeviceGbm *render_device_gbm)
+{
+}
+
+MetaRenderDeviceGbm *
+meta_render_device_gbm_new (MetaBackend     *backend,
+                            MetaDeviceFile  *device_file,
+                            GError         **error)
+{
+  return g_initable_new (META_TYPE_RENDER_DEVICE_GBM,
+                         NULL, error,
+                         "backend", backend,
+                         "device-file", device_file,
+                         NULL);
+}
diff --git a/src/backends/native/meta-render-device-gbm.h b/src/backends/native/meta-render-device-gbm.h
new file mode 100644
index 0000000000..c831b0d407
--- /dev/null
+++ b/src/backends/native/meta-render-device-gbm.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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_RENDER_DEVICE_GBM_H
+#define META_RENDER_DEVICE_GBM_H
+
+#include "backends/native/meta-render-device-private.h"
+
+#define META_TYPE_RENDER_DEVICE_GBM (meta_render_device_gbm_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRenderDeviceGbm, meta_render_device_gbm,
+                      META, RENDER_DEVICE_GBM,
+                      MetaRenderDevice)
+
+MetaRenderDeviceGbm * meta_render_device_gbm_new (MetaBackend     *backend,
+                                                  MetaDeviceFile  *device_file,
+                                                  GError         **error);
+
+#endif /* META_RENDER_DEVICE_GBM_H */
diff --git a/src/backends/native/meta-render-device-private.h 
b/src/backends/native/meta-render-device-private.h
new file mode 100644
index 0000000000..f064160bc7
--- /dev/null
+++ b/src/backends/native/meta-render-device-private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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_RENDER_DEVICE_PRIVATE_H
+#define META_RENDER_DEVICE_PRIVATE_H
+
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include "backends/meta-egl.h"
+#include "backends/native/meta-device-pool.h"
+#include "backends/native/meta-render-device.h"
+
+struct _MetaRenderDeviceClass
+{
+  GObjectClass parent_class;
+
+  EGLDisplay (* create_egl_display) (MetaRenderDevice  *render_device,
+                                     GError           **error);
+};
+
+#endif /* META_RENDER_DEVICE_PRIVATE_H */
diff --git a/src/backends/native/meta-render-device-surfaceless.c 
b/src/backends/native/meta-render-device-surfaceless.c
new file mode 100644
index 0000000000..fbeea3a7c9
--- /dev/null
+++ b/src/backends/native/meta-render-device-surfaceless.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020-2021 Red Hat Inc.
+ *
+ * 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-render-device-surfaceless.h"
+
+#include "backends/meta-backend-private.h"
+#include "backends/meta-egl.h"
+
+struct _MetaRenderDeviceSurfaceless
+{
+  MetaRenderDevice parent;
+};
+
+G_DEFINE_TYPE (MetaRenderDeviceSurfaceless, meta_render_device_surfaceless,
+               META_TYPE_RENDER_DEVICE)
+
+static EGLDisplay
+meta_render_device_surfaceless_create_egl_display (MetaRenderDevice  *render_device,
+                                                   GError           **error)
+{
+  MetaBackend *backend = meta_render_device_get_backend (render_device);
+  MetaEgl *egl = meta_backend_get_egl (backend);
+  EGLDisplay egl_display;
+
+  if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL,
+                                "EGL_MESA_platform_surfaceless",
+                                NULL))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Missing EGL platform required for surfaceless context: "
+                   "EGL_MESA_platform_surfaceless");
+      return EGL_NO_DISPLAY;
+    }
+
+  egl_display = meta_egl_get_platform_display (egl,
+                                               EGL_PLATFORM_SURFACELESS_MESA,
+                                               EGL_DEFAULT_DISPLAY,
+                                               NULL, error);
+  if (egl_display == EGL_NO_DISPLAY)
+    return EGL_NO_DISPLAY;
+
+  if (!meta_egl_initialize (egl, egl_display, error))
+    {
+      meta_egl_terminate (egl, egl_display, NULL);
+      return EGL_NO_DISPLAY;
+    }
+
+  return egl_display;
+}
+
+static void
+meta_render_device_surfaceless_class_init (MetaRenderDeviceSurfacelessClass *klass)
+{
+  MetaRenderDeviceClass *render_device_class = META_RENDER_DEVICE_CLASS (klass);
+
+  render_device_class->create_egl_display =
+    meta_render_device_surfaceless_create_egl_display;
+}
+
+static void
+meta_render_device_surfaceless_init (MetaRenderDeviceSurfaceless *render_device_surfaceless)
+{
+}
+
+MetaRenderDeviceSurfaceless *
+meta_render_device_surfaceless_new (MetaBackend  *backend,
+                                    GError      **error)
+{
+  return g_initable_new (META_TYPE_RENDER_DEVICE_SURFACELESS,
+                         NULL, error,
+                         "backend", backend,
+                         NULL);
+}
diff --git a/src/backends/native/meta-render-device-surfaceless.h 
b/src/backends/native/meta-render-device-surfaceless.h
new file mode 100644
index 0000000000..b85fc6eeba
--- /dev/null
+++ b/src/backends/native/meta-render-device-surfaceless.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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_RENDER_DEVICE_SURFACELESS_H
+#define META_RENDER_DEVICE_SURFACELESS_H
+
+#include "backends/native/meta-render-device-private.h"
+
+#define META_TYPE_RENDER_DEVICE_SURFACELESS (meta_render_device_surfaceless_get_type ())
+G_DECLARE_FINAL_TYPE (MetaRenderDeviceSurfaceless, meta_render_device_surfaceless,
+                      META, RENDER_DEVICE_SURFACELESS,
+                      MetaRenderDevice)
+
+MetaRenderDeviceSurfaceless * meta_render_device_surfaceless_new (MetaBackend  *backend,
+                                                                  GError      **error);
+
+#endif /* META_RENDER_DEVICE_SURFACELESS_H */
diff --git a/src/backends/native/meta-render-device.c b/src/backends/native/meta-render-device.c
new file mode 100644
index 0000000000..d696f7fe03
--- /dev/null
+++ b/src/backends/native/meta-render-device.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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-render-device-private.h"
+
+#include "backends/meta-backend-private.h"
+#include "backends/meta-egl.h"
+
+enum
+{
+  PROP_0,
+
+  PROP_BACKEND,
+  PROP_DEVICE_FILE,
+
+  N_PROPS
+};
+
+static GParamSpec *obj_props[N_PROPS];
+
+typedef struct _MetaRenderDevicePrivate
+{
+  MetaBackend *backend;
+
+  MetaDeviceFile *device_file;
+
+  EGLDisplay egl_display;
+  EGLConfig egl_config;
+
+  gboolean is_hardware_rendering;
+} MetaRenderDevicePrivate;
+
+static void
+initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaRenderDevice, meta_render_device,
+                                  G_TYPE_OBJECT,
+                                  G_ADD_PRIVATE (MetaRenderDevice)
+                                  G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                         initable_iface_init))
+
+static EGLDisplay
+meta_render_device_create_egl_display (MetaRenderDevice  *render_device,
+                                       GError           **error)
+{
+  MetaRenderDeviceClass *klass = META_RENDER_DEVICE_GET_CLASS (render_device);
+
+  return klass->create_egl_display (render_device, error);
+}
+
+static void
+detect_hardware_rendering (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+  MetaEgl *egl = meta_backend_get_egl (priv->backend);
+  g_autoptr (GError) error = NULL;
+  EGLint *attributes;
+  EGLContext egl_context;
+  const char *renderer_str;
+
+  attributes = (EGLint[]) {
+    EGL_CONTEXT_CLIENT_VERSION, 2,
+    EGL_NONE
+  };
+  egl_context = meta_egl_create_context (egl,
+                                         priv->egl_display,
+                                         EGL_NO_CONFIG_KHR,
+                                         EGL_NO_CONTEXT,
+                                         attributes,
+                                         &error);
+  if (egl_context == EGL_NO_CONTEXT)
+    {
+      meta_topic (META_DEBUG_RENDER, "Failed to create EGLContext for %s: %s",
+                  meta_device_file_get_path (priv->device_file),
+                  error->message);
+      return;
+    }
+
+  if (!meta_egl_make_current (egl,
+                              priv->egl_display,
+                              EGL_NO_SURFACE,
+                              EGL_NO_SURFACE,
+                              egl_context,
+                              &error))
+    {
+      g_warning ("Failed to detect hardware rendering: eglMakeCurrent(): %s",
+                 error->message);
+      goto out_has_context;
+    }
+
+  renderer_str = (const char *) glGetString (GL_RENDERER);
+  if (g_str_has_prefix (renderer_str, "llvmpipe") ||
+      g_str_has_prefix (renderer_str, "softpipe") ||
+      g_str_has_prefix (renderer_str, "swrast"))
+    goto out_has_context;
+
+  priv->is_hardware_rendering = TRUE;
+
+out_has_context:
+  meta_egl_destroy_context (egl, priv->egl_display, egl_context, NULL);
+}
+
+static void
+init_egl (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+  MetaEgl *egl = meta_backend_get_egl (priv->backend);
+  g_autoptr (GError) error = NULL;
+  EGLDisplay egl_display;
+
+  meta_egl_bind_api (egl, EGL_OPENGL_ES_API, NULL);
+
+  egl_display = meta_render_device_create_egl_display (render_device, &error);
+  if (egl_display == EGL_NO_DISPLAY)
+    {
+      meta_topic (META_DEBUG_RENDER, "Failed to create EGLDisplay for %s: %s",
+                  meta_device_file_get_path (priv->device_file),
+                  error->message);
+      return;
+    }
+
+  priv->egl_display = egl_display;
+  detect_hardware_rendering (render_device);
+}
+
+static gboolean
+meta_render_device_initable_init (GInitable     *initable,
+                                  GCancellable  *cancellable,
+                                  GError       **error)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (initable);
+
+  init_egl (render_device);
+
+  return TRUE;
+}
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+  initable_iface->init = meta_render_device_initable_init;
+}
+
+static void
+meta_render_device_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  switch (prop_id)
+    {
+    case PROP_BACKEND:
+      g_value_set_object (value, priv->backend);
+      break;
+    case PROP_DEVICE_FILE:
+      g_value_set_pointer (value, priv->device_file);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+meta_render_device_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  switch (prop_id)
+    {
+    case PROP_BACKEND:
+      priv->backend = g_value_get_object (value);
+      break;
+    case PROP_DEVICE_FILE:
+      priv->device_file = g_value_get_pointer (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+meta_render_device_dispose (GObject *object)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+  MetaEgl *egl = meta_backend_get_egl (priv->backend);
+
+  if (priv->egl_display != EGL_NO_DISPLAY)
+    {
+      meta_egl_terminate (egl, priv->egl_display, NULL);
+      priv->egl_display = EGL_NO_DISPLAY;
+    }
+
+  G_OBJECT_CLASS (meta_render_device_parent_class)->dispose (object);
+}
+
+static void
+meta_render_device_finalize (GObject *object)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  g_clear_pointer (&priv->device_file, meta_device_file_release);
+
+  G_OBJECT_CLASS (meta_render_device_parent_class)->finalize (object);
+}
+
+static void
+meta_render_device_constructed (GObject *object)
+{
+  MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  if (priv->device_file)
+    meta_device_file_acquire (priv->device_file);
+
+  G_OBJECT_CLASS (meta_render_device_parent_class)->constructed (object);
+}
+
+static void
+meta_render_device_class_init (MetaRenderDeviceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = meta_render_device_get_property;
+  object_class->set_property = meta_render_device_set_property;
+  object_class->constructed = meta_render_device_constructed;
+  object_class->dispose = meta_render_device_dispose;
+  object_class->finalize = meta_render_device_finalize;
+
+  obj_props[PROP_BACKEND] =
+    g_param_spec_object ("backend",
+                         "backend",
+                         "MetaBackend",
+                         META_TYPE_BACKEND,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+  obj_props[PROP_DEVICE_FILE] =
+    g_param_spec_pointer ("device-file",
+                          "device file",
+                          "MetaDeviceFile",
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+  g_object_class_install_properties (object_class, N_PROPS, obj_props);
+}
+
+static void
+meta_render_device_init (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  priv->egl_display = EGL_NO_DISPLAY;
+  priv->egl_config = EGL_NO_CONFIG_KHR;
+}
+
+MetaBackend *
+meta_render_device_get_backend (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  return priv->backend;
+}
+
+MetaDeviceFile *
+meta_render_device_get_device_file (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  return priv->device_file;
+}
+
+EGLDisplay
+meta_render_device_get_egl_display (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  return priv->egl_display;
+}
+
+gboolean
+meta_render_device_is_hardware_accelerated (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  return priv->is_hardware_rendering;
+}
+
+const char *
+meta_render_device_get_name (MetaRenderDevice *render_device)
+{
+  MetaRenderDevicePrivate *priv =
+    meta_render_device_get_instance_private (render_device);
+
+  if (priv->device_file)
+    return meta_device_file_get_path (priv->device_file);
+  else
+    return "(device-less)";
+}
diff --git a/src/backends/native/meta-render-device.h b/src/backends/native/meta-render-device.h
new file mode 100644
index 0000000000..b1b71028e9
--- /dev/null
+++ b/src/backends/native/meta-render-device.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 Red Hat Inc.
+ *
+ * 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_RENDER_DEVICE_H
+#define META_RENDER_DEVICE_H
+
+#include <glib-object.h>
+
+#include "backends/meta-backend-types.h"
+
+#define META_TYPE_RENDER_DEVICE (meta_render_device_get_type ())
+G_DECLARE_DERIVABLE_TYPE (MetaRenderDevice, meta_render_device,
+                          META, RENDER_DEVICE,
+                          GObject)
+
+MetaBackend * meta_render_device_get_backend (MetaRenderDevice *render_device);
+
+EGLDisplay meta_render_device_get_egl_display (MetaRenderDevice *render_device);
+
+const char * meta_render_device_get_name (MetaRenderDevice *render_device);
+
+gboolean meta_render_device_is_hardware_accelerated (MetaRenderDevice *render_device);
+
+MetaDeviceFile * meta_render_device_get_device_file (MetaRenderDevice *render_device);
+
+#endif /* META_RENDER_DEVICE_H */
diff --git a/src/meson.build b/src/meson.build
index f3aebfb285..f4ecba3b31 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -460,6 +460,13 @@ mutter_sources = [
   'x11/xprops.h',
 ]
 
+if have_egl_device
+  mutter_sources += [
+    'backends/native/meta-render-device-egl-stream.c',
+    'backends/native/meta-render-device-egl-stream.h',
+  ]
+endif
+
 if have_egl
   mutter_sources += [
     'backends/meta-egl.c',
@@ -748,6 +755,13 @@ if have_native_backend
     'backends/native/meta-onscreen-native.h',
     'backends/native/meta-pointer-constraint-native.c',
     'backends/native/meta-pointer-constraint-native.h',
+    'backends/native/meta-render-device-gbm.c',
+    'backends/native/meta-render-device-gbm.h',
+    'backends/native/meta-render-device-private.h',
+    'backends/native/meta-render-device-surfaceless.c',
+    'backends/native/meta-render-device-surfaceless.h',
+    'backends/native/meta-render-device.c',
+    'backends/native/meta-render-device.h',
     'backends/native/meta-renderer-native-gles3.c',
     'backends/native/meta-renderer-native-gles3.h',
     'backends/native/meta-renderer-native-private.h',


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