[801/906] context: Reimplement GL context sharing
authorMatthew Waters <ystreet00@gmail.com>
Thu, 29 Aug 2013 10:10:42 +0000 (20:10 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:31 +0000 (19:31 +0000)
https://bugzilla.gnome.org/show_bug.cgi?id=704806

gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m
gst-libs/gst/gl/egl/gstglcontext_egl.c
gst-libs/gst/gl/gstglcontext.c
gst-libs/gst/gl/gstglcontext.h
gst-libs/gst/gl/win32/gstglcontext_wgl.c
gst-libs/gst/gl/x11/gstglcontext_glx.c

index 510b09e..e808f37 100644 (file)
@@ -28,7 +28,7 @@
 #include "gstgl_cocoa_private.h"
 
 static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
-    guintptr external_opengl_context, GError **error);
+    GstGLContext * other_context, GError **error);
 static guintptr gst_gl_context_cocoa_get_gl_context (GstGLContext * window);
 static gboolean gst_gl_context_cocoa_activate (GstGLContext * context, gboolean activate);
 static GstGLAPI gst_gl_context_cocoa_get_gl_api (GstGLContext * context);
@@ -84,7 +84,7 @@ gst_gl_context_cocoa_new (void)
 
 static gboolean
 gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
-    guintptr external_gl_context, GError **error)
+    GstGLContext *other_context, GError **error)
 {
   GstGLContextCocoa *context_cocoa = GST_GL_CONTEXT_COCOA (context);
   GstGLContextCocoaPrivate *priv = context_cocoa->priv;
@@ -103,7 +103,10 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
   };
 
   priv->gl_context = nil;
-  priv->external_gl_context = (NSOpenGLContext *) external_gl_context;
+  if (other_context)
+    priv->external_gl_context = (NSOpenGLContext *) gst_gl_context_get_gl_context (other_context);
+  else
+    priv->external_gl_context = NULL;
 
   GSRegisterCurrentThread();
 
@@ -146,7 +149,9 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
   context_cocoa->priv->gl_context = glContext;
 
   [glView setOpenGLContext:glContext];
+
 #else
+  /* FIXME try to make context sharing work in GNUstep */
   context_cocoa->priv->gl_context = [glView openGLContext];
 #endif
 
index 3ef5075..6864dd0 100644 (file)
 #include "config.h"
 #endif
 
+/* FIXME: Sharing contexts requires the EGLDisplay & EGLConfig to be the same
+ * may need to box it.
+ */
+
 #include "gstglcontext_egl.h"
 #include <gst/gl/gl.h>
 
@@ -33,7 +37,7 @@
 #endif
 
 static gboolean gst_gl_context_egl_create_context (GstGLContext * context,
-    GstGLAPI gl_api, guintptr external_gl_context, GError ** error);
+    GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
 static void gst_gl_context_egl_destroy_context (GstGLContext * context);
 static gboolean gst_gl_context_egl_choose_format (GstGLContext * context,
     GError ** error);
@@ -150,27 +154,40 @@ gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error)
 }
 
 static gboolean
-gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GError ** error)
+gst_gl_context_egl_choose_config (GstGLContextEGL * egl,
+    GstGLContext * other_context, GError ** error)
 {
   EGLint numConfigs;
   gint i = 0;
   EGLint config_attrib[20];
 
-  config_attrib[i++] = EGL_SURFACE_TYPE;
-  config_attrib[i++] = EGL_WINDOW_BIT;
-  config_attrib[i++] = EGL_RENDERABLE_TYPE;
-  if (egl->gl_api & GST_GL_API_GLES2)
-    config_attrib[i++] = EGL_OPENGL_ES2_BIT;
-  else
-    config_attrib[i++] = EGL_OPENGL_BIT;
-  config_attrib[i++] = EGL_DEPTH_SIZE;
-  config_attrib[i++] = 16;
-  config_attrib[i++] = EGL_NONE;
+  if (other_context) {
+    GstGLContextEGL *other_context_egl = GST_GL_CONTEXT_EGL (other_context);
+    EGLint config_id;
+
+    eglGetConfigAttrib (egl->egl_display, other_context_egl->egl_config,
+        EGL_CONFIG_ID, &config_id);
+
+    config_attrib[i++] = EGL_CONFIG_ID;
+    config_attrib[i++] = config_id;
+    config_attrib[i++] = EGL_NONE;
+  } else {
+    config_attrib[i++] = EGL_SURFACE_TYPE;
+    config_attrib[i++] = EGL_WINDOW_BIT;
+    config_attrib[i++] = EGL_RENDERABLE_TYPE;
+    if (egl->gl_api & GST_GL_API_GLES2)
+      config_attrib[i++] = EGL_OPENGL_ES2_BIT;
+    else
+      config_attrib[i++] = EGL_OPENGL_BIT;
+    config_attrib[i++] = EGL_DEPTH_SIZE;
+    config_attrib[i++] = 16;
+    config_attrib[i++] = EGL_NONE;
+  }
 
   if (eglChooseConfig (egl->egl_display, config_attrib,
           &egl->egl_config, 1, &numConfigs)) {
-    GST_INFO ("config set: %ld, %ld", (gulong) egl->egl_config,
-        (gulong) numConfigs);
+    GST_INFO ("config set: %" G_GUINTPTR_FORMAT ", %u",
+        (guintptr) egl->egl_config, (unsigned int) numConfigs);
   } else {
     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
         "Failed to set window configuration: %s",
@@ -186,7 +203,7 @@ failure:
 
 static gboolean
 gst_gl_context_egl_create_context (GstGLContext * context,
-    GstGLAPI gl_api, guintptr external_gl_context, GError ** error)
+    GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
 {
   GstGLContextEGL *egl;
   GstGLWindow *window = NULL;
@@ -197,19 +214,33 @@ gst_gl_context_egl_create_context (GstGLContext * context,
   EGLint minorVersion;
   const gchar *egl_exts;
   gboolean need_surface = TRUE;
+  guintptr external_gl_context = 0;
 
   egl = GST_GL_CONTEXT_EGL (context);
   window = gst_gl_context_get_window (context);
 
-  if ((gl_api & GST_GL_API_OPENGL) == GST_GL_API_NONE &&
-      (gl_api & GST_GL_API_GLES2) == GST_GL_API_NONE) {
+  if (other_context) {
+    if (!GST_GL_IS_CONTEXT_EGL (other_context)) {
+      g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG,
+          "Cannot share context with non-EGL context");
+      goto failure;
+    }
+    external_gl_context = gst_gl_context_get_gl_context (other_context);
+  }
+
+  if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) {
     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
-        "xEGL supports opengl or gles2");
+        "EGL supports opengl or gles2");
     goto failure;
   }
 
-  egl->egl_display =
-      eglGetDisplay ((EGLNativeDisplayType) gst_gl_window_get_display (window));
+  if (other_context) {
+    GstGLContextEGL *other_egl = (GstGLContextEGL *) other_context;
+    egl->egl_display = other_egl->egl_display;
+  } else {
+    egl->egl_display = eglGetDisplay ((EGLNativeDisplayType)
+        gst_gl_window_get_display (window));
+  }
 
   if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) {
     GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion);
@@ -245,11 +276,12 @@ gst_gl_context_egl_create_context (GstGLContext * context,
 
     if (!eglBindAPI (EGL_OPENGL_API)) {
       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
-          "Failed to bind OpenGL|ES API: %s",
+          "Failed to bind OpenGL API: %s",
           gst_gl_context_egl_get_error_string ());
       goto failure;
     }
 
+    GST_INFO ("Using OpenGL");
     egl->gl_api = GST_GL_API_OPENGL;
   } else if (gl_api & GST_GL_API_GLES2) {
   try_gles2:
@@ -260,10 +292,11 @@ gst_gl_context_egl_create_context (GstGLContext * context,
       goto failure;
     }
 
+    GST_INFO ("Using OpenGL|ES 2.0");
     egl->gl_api = GST_GL_API_GLES2;
   }
 
-  if (!gst_gl_context_egl_choose_config (egl, error)) {
+  if (!gst_gl_context_egl_choose_config (egl, other_context, error)) {
     g_assert (error == NULL || *error != NULL);
     goto failure;
   }
@@ -281,7 +314,8 @@ gst_gl_context_egl_create_context (GstGLContext * context,
       (EGLContext) external_gl_context, context_attrib);
 
   if (egl->egl_context != EGL_NO_CONTEXT) {
-    GST_INFO ("gl context created: %ld", (gulong) egl->egl_context);
+    GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT,
+        (guintptr) egl->egl_context);
   } else {
     g_set_error (error, GST_GL_CONTEXT_ERROR,
         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
@@ -292,17 +326,19 @@ gst_gl_context_egl_create_context (GstGLContext * context,
 
   egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS);
 
-  /* FIXME do we want a window vfunc ? */
+  if (other_context == NULL) {
+    /* FIXME do we want a window vfunc ? */
 #if GST_GL_HAVE_WINDOW_X11
-  if (GST_GL_IS_WINDOW_X11 (context->window)) {
-    gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window);
-  }
+    if (GST_GL_IS_WINDOW_X11 (context->window)) {
+      gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window);
+    }
 #endif
 #if GST_GL_HAVE_WINDOW_WIN32
-  if (GST_GL_IS_WINDOW_WIN32 (context->window)) {
-    gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window);
-  }
+    if (GST_GL_IS_WINDOW_WIN32 (context->window)) {
+      gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window);
+    }
 #endif
+  }
 
   window_handle = gst_gl_window_get_window_handle (window);
 
index c2d20a7..f459de7 100644 (file)
@@ -72,7 +72,7 @@ struct _GstGLContextPrivate
   gboolean created;
   gboolean alive;
 
-  guintptr external_gl_context;
+  GstGLContext *other_context;
   GstGLAPI gl_api;
   GError **error;
 };
@@ -299,7 +299,7 @@ gst_gl_context_get_window (GstGLContext * context)
 /* Create an opengl context (one context for one GstGLDisplay) */
 gboolean
 gst_gl_context_create (GstGLContext * context,
-    guintptr external_gl_context, GError ** error)
+    GstGLContext * other_context, GError ** error)
 {
   gboolean alive = FALSE;
 
@@ -310,7 +310,7 @@ gst_gl_context_create (GstGLContext * context,
   g_mutex_lock (&context->priv->render_lock);
 
   if (!context->priv->created) {
-    context->priv->external_gl_context = external_gl_context;
+    context->priv->other_context = other_context;
     context->priv->error = error;
 
     context->priv->gl_thread = g_thread_new ("gstglcontext",
@@ -476,7 +476,7 @@ _parse_gl_api (const gchar * apis_s)
 }
 
 //gboolean
-//gst_gl_context_create (GstGLContext * context, guintptr external_gl_context, GError ** error)
+//gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error)
 static gpointer
 gst_gl_context_create_thread (GstGLContext * context)
 {
@@ -492,12 +492,12 @@ gst_gl_context_create_thread (GstGLContext * context)
   gchar *user_api_string;
   const gchar *user_choice;
   GError **error;
-  guintptr external_gl_context;
+  GstGLContext *other_context;
 
   g_mutex_lock (&context->priv->render_lock);
 
   error = context->priv->error;
-  external_gl_context = context->priv->external_gl_context;
+  other_context = context->priv->other_context;
 
   context_class = GST_GL_CONTEXT_GET_CLASS (context);
   window_class = GST_GL_WINDOW_GET_CLASS (context->window);
@@ -539,7 +539,7 @@ gst_gl_context_create_thread (GstGLContext * context)
       "compiled api support (%s)", user_api_string, compiled_api_s);
 
   if (!context_class->create_context (context, compiled_api & user_api,
-          external_gl_context, error)) {
+          other_context, error)) {
     g_assert (error == NULL || *error != NULL);
     g_free (compiled_api_s);
     g_free (user_api_string);
index 68d6f05..21db7e8 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <gst/gst.h>
 
-#include <gst/gl/gstgl_fwd.h>
+#include <gst/gl/gl.h>
 
 G_BEGIN_DECLS
 
@@ -71,7 +71,7 @@ struct _GstGLContextClass {
   gboolean (*activate)           (GstGLContext *context, gboolean activate);
   gboolean (*choose_format)      (GstGLContext *context, GError **error);
   gboolean (*create_context)     (GstGLContext *context, GstGLAPI gl_api,
-                                  guintptr external_gl_context, GError ** error);
+                                  GstGLContext *other_context, GError ** error);
   void     (*destroy_context)    (GstGLContext *context);
   void     (*swap_buffers)       (GstGLContext *context);
 
@@ -88,8 +88,9 @@ gboolean      gst_gl_context_activate         (GstGLContext *context, gboolean a
 gpointer      gst_gl_context_get_proc_address (GstGLContext *context, const gchar *name);
 GstGLPlatform gst_gl_context_get_platform     (GstGLContext *context);
 GstGLAPI      gst_gl_context_get_gl_api       (GstGLContext *context);
+guintptr      gst_gl_context_get_gl_context   (GstGLContext *context);
 
-gboolean      gst_gl_context_create           (GstGLContext *context, guintptr external_gl_context, GError ** error);
+gboolean      gst_gl_context_create           (GstGLContext *context, GstGLContext *other_context, GError ** error);
 
 gpointer      gst_gl_context_default_get_proc_address (GstGLContext *context, const gchar *name);
 
index 826ab44..88e35af 100644 (file)
@@ -40,7 +40,7 @@ static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context,
 static gboolean gst_gl_context_wgl_activate (GstGLContext * context,
     gboolean activate);
 static gboolean gst_gl_context_wgl_create_context (GstGLContext * context,
-    GstGLAPI gl_api, guintptr external_gl_context, GError ** error);
+    GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
 static void gst_gl_context_wgl_destroy_context (GstGLContext * context);
 GstGLAPI gst_gl_context_wgl_get_gl_api (GstGLContext * context);
 static gpointer gst_gl_context_wgl_get_proc_address (GstGLContext * context,
@@ -84,23 +84,33 @@ gst_gl_context_wgl_new (void)
 
 static gboolean
 gst_gl_context_wgl_create_context (GstGLContext * context,
-    GstGLAPI gl_api, guintptr external_gl_context, GError ** error)
+    GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
 {
   GstGLWindow *window;
   GstGLContextWGL *context_wgl;
+  GstGLContextWGL *other_wgl = NULL;
   HDC device;
 
   context_wgl = GST_GL_CONTEXT_WGL (context);
   window = gst_gl_context_get_window (context);
   device = (HDC) gst_gl_window_get_display (window);
 
+  if (other_context) {
+    if (!GST_GL_IS_CONTEXT_WGL (other_context)) {
+      g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG,
+          "Cannot share context with a non-WGL context");
+      goto failure;
+    }
+    other_wgl = (GstGLContextWGL *) other_context;
+  }
+
   context_wgl->wgl_context = wglCreateContext (device);
   if (context_wgl->wgl_context)
     GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT,
         (guintptr) context_wgl->wgl_context);
   else {
     g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_CREATE_CONTEXT,
-        "failed to create glcontext:%lu", GetLastError ());
+        "failed to create glcontext:0x%x", (unsigned int) GetLastError ());
     goto failure;
   }
   g_assert (context_wgl->wgl_context);
@@ -108,6 +118,15 @@ gst_gl_context_wgl_create_context (GstGLContext * context,
   GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT,
       (guintptr) context_wgl->wgl_context);
 
+  if (other_wgl) {
+    if (!wglShareLists (other_wgl->wgl_context, context_wgl->wgl_context)) {
+      g_set_error (error, GST_GL_WINDOW_ERROR,
+          GST_GL_WINDOW_ERROR_CREATE_CONTEXT, "failed to share contexts 0x%x",
+          (unsigned int) GetLastError ());
+      goto failure;
+    }
+  }
+
   gst_object_unref (window);
 
   return TRUE;
index 86c9d8a..abfec94 100644 (file)
 #include "config.h"
 #endif
 
+/* FIXME: Sharing contexts requires the Display to be the same.
+ * May need to box it
+ */
+
 #include <gst/gst.h>
 
 #include "../gstgl_fwd.h"
@@ -46,7 +50,7 @@ static void gst_gl_context_glx_swap_buffers (GstGLContext * context);
 static gboolean gst_gl_context_glx_activate (GstGLContext * context,
     gboolean activate);
 static gboolean gst_gl_context_glx_create_context (GstGLContext *
-    context, GstGLAPI gl_api, guintptr external_gl_context, GError ** error);
+    context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
 static void gst_gl_context_glx_destroy_context (GstGLContext * context);
 static gboolean gst_gl_context_glx_choose_format (GstGLContext *
     context, GError ** error);
@@ -129,7 +133,7 @@ _describe_fbconfig (Display * display, GLXFBConfig config)
 
 static gboolean
 gst_gl_context_glx_create_context (GstGLContext * context,
-    GstGLAPI gl_api, guintptr external_gl_context, GError ** error)
+    GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
 {
   GstGLContextGLX *context_glx;
   GstGLWindow *window;
@@ -138,11 +142,28 @@ gst_gl_context_glx_create_context (GstGLContext * context,
   const char *glx_exts;
   int x_error;
   Display *device;
+  guintptr external_gl_context = 0;
 
   context_glx = GST_GL_CONTEXT_GLX (context);
   window = gst_gl_context_get_window (context);
   window_x11 = GST_GL_WINDOW_X11 (window);
-  device = (Display *) gst_gl_window_get_display (window);
+
+  if (other_context) {
+    GstGLWindow *other_window;
+
+    if (!GST_GL_IS_CONTEXT_GLX (other_context)) {
+      g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG,
+          "Cannot share context with non-GLX context");
+      goto failure;
+    }
+
+    other_window = gst_gl_context_get_window (other_context);
+    external_gl_context = gst_gl_context_get_gl_context (other_context);
+    device = (Display *) gst_gl_window_get_display (other_window);
+    gst_object_unref (other_window);
+  } else {
+    device = (Display *) gst_gl_window_get_display (window);
+  }
 
   glx_exts = glXQueryExtensionsString (device, DefaultScreen (device));