[gnome-remote-desktop] Introduce an EGL thread
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-remote-desktop] Introduce an EGL thread
- Date: Wed, 8 Dec 2021 09:09:50 +0000 (UTC)
commit 722ceaf0120ffad593d082c2757743411477759a
Author: Jonas Ådahl <jadahl gmail com>
Date: Fri Oct 8 11:42:45 2021 +0200
Introduce an EGL thread
It does nothing more than up a thread with a main loop, but will be used
to download DMA buffers to CPU memory.
meson.build | 2 +
src/grd-egl-thread.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++
src/grd-egl-thread.h | 32 ++++++++
src/meson.build | 5 ++
tests/egl-thread-test.c | 39 +++++++++
tests/meson.build | 16 ++++
6 files changed, 305 insertions(+)
---
diff --git a/meson.build b/meson.build
index 06fbe1c..7914eeb 100644
--- a/meson.build
+++ b/meson.build
@@ -8,6 +8,7 @@ freerdp_req = '>= 2.3.0'
fuse_req = '>= 3.9.1'
nvenc_req = '>= 11'
xkbcommon_req = '>= 1.0.0'
+epoxy_req = '>= 1.4'
gnome = import('gnome')
i18n = import('i18n')
@@ -22,6 +23,7 @@ pipewire_dep = dependency('libpipewire-0.3', version: '>= 0.3.0')
systemd_dep = dependency('systemd', required: get_option('systemd'))
libsecret_dep = dependency('libsecret-1')
libnotify_dep = dependency('libnotify')
+epoxy_dep = dependency('epoxy')
have_rdp = get_option('rdp')
have_vnc = get_option('vnc')
diff --git a/src/grd-egl-thread.c b/src/grd-egl-thread.c
new file mode 100644
index 0000000..5abff48
--- /dev/null
+++ b/src/grd-egl-thread.c
@@ -0,0 +1,211 @@
+/*
+ * 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 "grd-egl-thread.h"
+
+#include <epoxy/egl.h>
+#include <epoxy/gl.h>
+#include <gio/gio.h>
+
+struct _GrdEglThread
+{
+ GThread *thread;
+ GMutex mutex;
+ GCond cond;
+
+ GAsyncQueue *task_queue;
+
+ struct
+ {
+ gboolean initialized;
+ GError *error;
+
+ GMainContext *main_context;
+ GMainLoop *main_loop;
+
+ EGLDisplay egl_display;
+ EGLContext egl_context;
+ } impl;
+};
+
+static gboolean
+grd_egl_init_in_impl (GrdEglThread *egl_thread,
+ GError **error)
+{
+ EGLDisplay egl_display;
+ EGLint major, minor;
+ EGLContext egl_context;
+
+ if (!epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Missing extension 'EGL_EXT_platform_base'");
+ return FALSE;
+ }
+
+ egl_display = eglGetPlatformDisplayEXT (EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL);
+ if (egl_display == EGL_NO_DISPLAY)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to get EGL display");
+ return FALSE;
+ }
+
+ if (!eglInitialize (egl_display, &major, &minor))
+ {
+ eglTerminate (egl_display);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to initialize EGL display");
+ return FALSE;
+ }
+
+ if (!eglBindAPI (EGL_OPENGL_ES_API))
+ {
+ eglTerminate (egl_display);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to bind OpenGL ES API");
+ return FALSE;
+ }
+
+ if (!epoxy_has_egl_extension (egl_display, "EGL_MESA_platform_surfaceless"))
+ {
+ eglTerminate (egl_display);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Missing extension 'EGL_MESA_platform_surfaceless'");
+ return FALSE;
+ }
+
+ if (!epoxy_has_egl_extension (egl_display, "EGL_MESA_configless_context"))
+ {
+ eglTerminate (egl_display);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Missing extension 'EGL_MESA_platform_surfaceless'");
+ return FALSE;
+ }
+
+ egl_context = eglCreateContext (egl_display, EGL_NO_CONFIG_KHR, NULL, NULL);
+ if (egl_context == EGL_NO_CONTEXT)
+ {
+ eglTerminate (egl_display);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Failed to create EGL context");
+ return FALSE;
+ }
+
+ egl_thread->impl.egl_display = egl_display;
+ egl_thread->impl.egl_context = egl_context;
+
+ return TRUE;
+}
+
+static gpointer
+grd_egl_thread_func (gpointer user_data)
+{
+ GrdEglThread *egl_thread = user_data;
+ GError *error = NULL;
+
+ egl_thread->impl.main_context = g_main_context_new ();
+
+ if (!grd_egl_init_in_impl (egl_thread, &error))
+ {
+ g_propagate_error (&egl_thread->impl.error, error);
+ g_mutex_lock (&egl_thread->mutex);
+ egl_thread->impl.initialized = TRUE;
+ g_cond_signal (&egl_thread->cond);
+ g_mutex_unlock (&egl_thread->mutex);
+ return NULL;
+ }
+
+ egl_thread->impl.main_loop = g_main_loop_new (egl_thread->impl.main_context,
+ FALSE);
+ g_mutex_lock (&egl_thread->mutex);
+ egl_thread->impl.initialized = TRUE;
+ g_cond_signal (&egl_thread->cond);
+ g_mutex_unlock (&egl_thread->mutex);
+
+ g_main_loop_run (egl_thread->impl.main_loop);
+
+ g_clear_pointer (&egl_thread->impl.main_loop, g_main_loop_unref);
+
+ eglDestroyContext (egl_thread->impl.egl_display,
+ egl_thread->impl.egl_context);
+ eglTerminate (egl_thread->impl.egl_display);
+
+ return NULL;
+}
+
+GrdEglThread *
+grd_egl_thread_new (GError **error)
+{
+ GrdEglThread *egl_thread;
+
+ egl_thread = g_new0 (GrdEglThread, 1);
+ g_mutex_init (&egl_thread->mutex);
+ g_cond_init (&egl_thread->cond);
+
+ g_mutex_lock (&egl_thread->mutex);
+
+ egl_thread->thread = g_thread_new ("GRD EGL thread", grd_egl_thread_func, egl_thread);
+
+ while (!egl_thread->impl.initialized)
+ g_cond_wait (&egl_thread->cond, &egl_thread->mutex);
+ g_mutex_unlock (&egl_thread->mutex);
+
+ if (egl_thread->impl.error)
+ {
+ g_propagate_error (error, egl_thread->impl.error);
+ grd_egl_thread_free (egl_thread);
+ return NULL;
+ }
+
+ return egl_thread;
+}
+
+static gboolean
+quit_main_loop_in_impl (gpointer user_data)
+{
+ GrdEglThread *egl_thread = user_data;
+
+ if (egl_thread->impl.main_loop)
+ g_main_loop_quit (egl_thread->impl.main_loop);
+
+ return G_SOURCE_REMOVE;
+}
+
+void
+grd_egl_thread_free (GrdEglThread *egl_thread)
+{
+ GSource *source;
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, quit_main_loop_in_impl, egl_thread, NULL);
+ g_source_attach (source, egl_thread->impl.main_context);
+ g_source_unref (source);
+
+ g_thread_join (egl_thread->thread);
+ g_mutex_clear (&egl_thread->mutex);
+ g_cond_clear (&egl_thread->cond);
+
+ g_clear_pointer (&egl_thread->impl.main_context, g_main_context_unref);
+
+ g_free (egl_thread);
+}
diff --git a/src/grd-egl-thread.h b/src/grd-egl-thread.h
new file mode 100644
index 0000000..0dabf1e
--- /dev/null
+++ b/src/grd-egl-thread.h
@@ -0,0 +1,32 @@
+/*
+ * 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 GRD_EGL_THREAD_H
+#define GRD_EGL_THREAD_H
+
+#include <glib.h>
+
+typedef struct _GrdEglThread GrdEglThread;
+
+GrdEglThread * grd_egl_thread_new (GError **error);
+
+void grd_egl_thread_free (GrdEglThread *egl_thread);
+
+#endif /* GRD_EGL_THREAD_H */
diff --git a/src/meson.build b/src/meson.build
index 2fe3923..a65a62b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,3 +1,5 @@
+src_includepath = include_directories('.')
+
deps = [
cairo_dep,
glib_dep,
@@ -6,6 +8,7 @@ deps = [
pipewire_dep,
libsecret_dep,
libnotify_dep,
+ epoxy_dep,
]
daemon_sources = files([
@@ -13,6 +16,8 @@ daemon_sources = files([
'grd-clipboard.h',
'grd-context.c',
'grd-context.h',
+ 'grd-egl-thread.c',
+ 'grd-egl-thread.h',
'grd-daemon.c',
'grd-daemon.h',
'grd-damage-utils.c',
diff --git a/tests/egl-thread-test.c b/tests/egl-thread-test.c
new file mode 100644
index 0000000..b6d387d
--- /dev/null
+++ b/tests/egl-thread-test.c
@@ -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.
+ *
+ */
+
+#include "config.h"
+
+#include "grd-egl-thread.h"
+
+int
+main (int argc,
+ char **argv)
+{
+ GError *error = NULL;
+ GrdEglThread *egl_thread;
+
+ egl_thread = grd_egl_thread_new (&error);
+ if (!egl_thread)
+ g_error ("Failed to start EGL thread: %s", error->message);
+
+ grd_egl_thread_free (egl_thread);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/meson.build b/tests/meson.build
index 978ae23..a82c261 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -20,3 +20,19 @@ if have_vnc
timeout: 10,
)
endif
+
+egl_thread_test = executable(
+ 'egl-thread-test',
+ sources: [
+ 'egl-thread-test.c',
+ '../src/grd-egl-thread.c',
+ '../src/grd-egl-thread.h',
+ ],
+ dependencies: deps,
+ include_directories: [
+ src_includepath,
+ configinc,
+ ],
+)
+
+test('egl-thread', egl_thread_test)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]