From 2047d2d4e9ab38586f6c3cbb7508b4837941bd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 3 May 2021 19:23:52 +0200 Subject: [PATCH] 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: --- .../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 ++ .../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(+) create mode 100644 src/backends/native/meta-render-device-egl-stream.c create mode 100644 src/backends/native/meta-render-device-egl-stream.h create mode 100644 src/backends/native/meta-render-device-gbm.c create mode 100644 src/backends/native/meta-render-device-gbm.h create mode 100644 src/backends/native/meta-render-device-private.h create mode 100644 src/backends/native/meta-render-device-surfaceless.c create mode 100644 src/backends/native/meta-render-device-surfaceless.h create mode 100644 src/backends/native/meta-render-device.c create mode 100644 src/backends/native/meta-render-device.h 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 000000000..fa287a66d --- /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 000000000..b4b66b8b1 --- /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 000000000..5dc99d379 --- /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 + +#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 000000000..c831b0d40 --- /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 000000000..f064160bc --- /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 +#include + +#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 000000000..fbeea3a7c --- /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 000000000..b85fc6eeb --- /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 000000000..d696f7fe0 --- /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 000000000..b1b71028e --- /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 + +#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 f3aebfb28..f4ecba3b3 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',