[mutter/wip/carlosg/drop-caps: 1/7] cogl: Defer EGLContext creation to a separate thread



commit 1399cb28c36ae49309f9e69f35fb4e153fe8bf95
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Nov 8 14:33:52 2019 +0100

    cogl: Defer EGLContext creation to a separate thread
    
    This is rather pointless and complex at the moment, but will pay
    off as we can then spawn this thread early enough that it keeps
    capabilities to create high priority contexts.
    
    https://gitlab.gnome.org/GNOME/mutter/merge_requests/923

 cogl/cogl/cogl-egl.h               |   8 +++
 cogl/cogl/winsys/cogl-winsys-egl.c | 132 +++++++++++++++++++++++++++++++++++--
 2 files changed, 136 insertions(+), 4 deletions(-)
---
diff --git a/cogl/cogl/cogl-egl.h b/cogl/cogl/cogl-egl.h
index b9c163126..98f3c5ad0 100644
--- a/cogl/cogl/cogl-egl.h
+++ b/cogl/cogl/cogl-egl.h
@@ -79,6 +79,14 @@ G_BEGIN_DECLS
 EGLDisplay
 cogl_egl_context_get_egl_display (CoglContext *context);
 
+gboolean cogl_egl_init_thread (void);
+
+EGLContext
+cogl_egl_create_context (EGLDisplay    display,
+                         EGLConfig     config,
+                         EGLContext    shared_context,
+                         const EGLint *attrib_list);
+
 G_END_DECLS
 
 /* The gobject introspection scanner seems to parse public headers in
diff --git a/cogl/cogl/winsys/cogl-winsys-egl.c b/cogl/cogl/winsys/cogl-winsys-egl.c
index 5dd106d1b..55ff97acf 100644
--- a/cogl/cogl/winsys/cogl-winsys-egl.c
+++ b/cogl/cogl/winsys/cogl-winsys-egl.c
@@ -110,6 +110,20 @@ static const CoglFeatureData winsys_feature_data[] =
 #include "winsys/cogl-winsys-egl-feature-functions.h"
   };
 
+static GMainContext *egl_thread_context = NULL;
+
+typedef struct _CreateEGLContextData
+{
+  EGLDisplay display;
+  EGLConfig config;
+  EGLContext shared_context;
+  const EGLint *attrib_list;
+  EGLContext context;
+  GMutex mutex;
+  GCond cond;
+  gboolean finished;
+} CreateEGLContextData;
+
 static GCallback
 _cogl_winsys_renderer_get_proc_address (CoglRenderer *renderer,
                                         const char *name,
@@ -386,10 +400,10 @@ try_create_context (CoglDisplay *display,
 
   attribs[i++] = EGL_NONE;
 
-  egl_display->egl_context = eglCreateContext (edpy,
-                                               config,
-                                               EGL_NO_CONTEXT,
-                                               attribs);
+  egl_display->egl_context = cogl_egl_create_context (edpy,
+                                                      config,
+                                                      EGL_NO_CONTEXT,
+                                                      attribs);
 
   if (egl_display->egl_context == EGL_NO_CONTEXT)
     {
@@ -965,3 +979,113 @@ cogl_egl_context_get_egl_display (CoglContext *context)
 
   return egl_renderer->edpy;
 }
+
+static gpointer
+init_egl_context_thread (gpointer data)
+{
+  GMainContext *main_context = data;
+  GMainLoop *main_loop = g_main_loop_new (main_context, FALSE);
+
+  g_main_loop_run (main_loop);
+  return NULL;
+}
+
+gboolean
+cogl_egl_init_thread (void)
+{
+  GMainContext *main_context;
+  GThread *thread;
+  GError *error = NULL;
+
+  if (egl_thread_context != NULL)
+    return TRUE;
+
+  main_context = g_main_context_new ();
+  thread = g_thread_try_new ("EGL context generator thread",
+                             init_egl_context_thread,
+                             main_context, &error);
+  if (!thread)
+    {
+      g_main_context_unref (main_context);
+      g_warning ("Failed to create EGL Context generator thread: %s",
+                 error->message);
+      g_error_free (error);
+
+      return FALSE;
+    }
+
+  egl_thread_context = main_context;
+
+  return TRUE;
+}
+
+static CreateEGLContextData *
+create_egl_context_data_new (EGLDisplay    display,
+                             EGLConfig     config,
+                             EGLContext    shared_context,
+                             const EGLint *attrib_list)
+{
+  CreateEGLContextData *data;
+
+  data = g_new0 (CreateEGLContextData, 1);
+  data->display = display;
+  data->config = config;
+  data->shared_context = shared_context;
+  data->attrib_list = attrib_list;
+  data->context = EGL_NO_CONTEXT;
+  g_mutex_init (&data->mutex);
+  g_cond_init (&data->cond);
+
+  return data;
+}
+
+/* Executed in the EGL context generator thread */
+static gboolean
+create_context_in_thread (gpointer user_data)
+{
+  CreateEGLContextData *data = user_data;
+
+  g_mutex_lock (&data->mutex);
+  data->context = eglCreateContext (data->display,
+                                    data->config,
+                                    data->shared_context,
+                                    data->attrib_list);
+  data->finished = TRUE;
+  g_cond_signal (&data->cond);
+  g_mutex_unlock (&data->mutex);
+
+  return G_SOURCE_REMOVE;
+}
+
+EGLContext
+cogl_egl_create_context (EGLDisplay    display,
+                         EGLConfig     config,
+                         EGLContext    shared_context,
+                         const EGLint *attrib_list)
+{
+  CreateEGLContextData *data;
+  EGLContext context;
+  GSource *source;
+
+  if (!cogl_egl_init_thread ())
+    return EGL_NO_CONTEXT;
+
+  data = create_egl_context_data_new (display, config,
+                                      shared_context, attrib_list);
+  g_mutex_lock (&data->mutex);
+
+  source = g_idle_source_new ();
+  g_source_set_callback (source, create_context_in_thread,
+                         data, NULL);
+  g_source_attach (source, egl_thread_context);
+  g_source_unref (source);
+
+  while (!data->finished)
+    g_cond_wait (&data->cond, &data->mutex);
+
+  context = data->context;
+  g_mutex_unlock (&data->mutex);
+  g_free (data);
+
+  return context;
+}


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