[891/906] context: add support for wrapping external contexts
authorMatthew Waters <ystreet00@gmail.com>
Mon, 10 Feb 2014 21:57:29 +0000 (08:57 +1100)
committerTim-Philipp Müller <tim@centricular.com>
Sat, 9 Dec 2017 19:31:33 +0000 (19:31 +0000)
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
tests/check/libs/gstglcontext.c

index c5ae84f..486763e 100644 (file)
@@ -33,6 +33,7 @@ static void gst_gl_context_cocoa_destroy_context (GstGLContext *context);
 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);
+static GstGLPlatform gst_gl_context_cocoa_get_gl_platform (GstGLContext * context);
 
 #define GST_GL_CONTEXT_COCOA_GET_PRIVATE(o)  \
   (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT_COCOA, GstGLContextCocoaPrivate))
@@ -85,6 +86,8 @@ gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass)
   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_activate);
   context_class->get_gl_api =
       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_api);
+  context_class->get_gl_platform =
+      GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_platform);
 
 #ifndef GNUSTEP
   pool = [[NSAutoreleasePool alloc] init];
@@ -255,3 +258,9 @@ gst_gl_context_cocoa_get_gl_api (GstGLContext * context)
 {
   return GST_GL_API_OPENGL;
 }
+
+static GstGLPlatform
+gst_gl_context_cocoa_get_gl_platform (GstGLContext * context)
+{
+  return GST_GL_API_COCOA;
+}
index 9aafd74..b181984 100644 (file)
@@ -48,6 +48,8 @@ static gboolean gst_gl_context_egl_activate (GstGLContext * context,
 static void gst_gl_context_egl_swap_buffers (GstGLContext * context);
 static guintptr gst_gl_context_egl_get_gl_context (GstGLContext * context);
 static GstGLAPI gst_gl_context_egl_get_gl_api (GstGLContext * context);
+static GstGLPlatform gst_gl_context_egl_get_gl_platform (GstGLContext *
+    context);
 static gpointer gst_gl_context_egl_get_proc_address (GstGLContext * context,
     const gchar * name);
 
@@ -71,6 +73,8 @@ gst_gl_context_egl_class_init (GstGLContextEGLClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_egl_swap_buffers);
 
   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_api);
+  context_class->get_gl_platform =
+      GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform);
   context_class->get_proc_address =
       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_proc_address);
 }
@@ -213,12 +217,14 @@ gst_gl_context_egl_create_context (GstGLContext * context,
   const gchar *egl_exts;
   gboolean need_surface = TRUE;
   guintptr external_gl_context = 0;
+  guintptr native_display;
+  GstGLDisplay *display;
 
   egl = GST_GL_CONTEXT_EGL (context);
   window = gst_gl_context_get_window (context);
 
   if (other_context) {
-    if (!GST_GL_IS_CONTEXT_EGL (other_context)) {
+    if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) {
       g_set_error (error, GST_GL_CONTEXT_ERROR,
           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
           "Cannot share context with non-EGL context");
@@ -462,6 +468,12 @@ gst_gl_context_egl_get_gl_api (GstGLContext * context)
   return GST_GL_CONTEXT_EGL (context)->gl_api;
 }
 
+static GstGLPlatform
+gst_gl_context_egl_get_gl_platform (GstGLContext * context)
+{
+  return GST_GL_PLATFORM_EGL;
+}
+
 static gpointer
 gst_gl_context_egl_get_proc_address (GstGLContext * context, const gchar * name)
 {
index c385682..d190502 100644 (file)
@@ -95,6 +95,31 @@ struct _GstGLContextPrivate
   GError **error;
 };
 
+typedef struct
+{
+  GstGLContext parent;
+
+  guintptr handle;
+  GstGLPlatform platform;
+  GstGLAPI available_apis;
+} GstGLWrappedContext;
+
+typedef struct
+{
+  GstGLContextClass parent;
+} GstGLWrappedContextClass;
+
+#define GST_GL_TYPE_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type())
+GType gst_gl_wrapped_context_get_type (void);
+G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
+    GST_GL_TYPE_CONTEXT);
+
+#define GST_GL_WRAPPED_CONTEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WRAPPED_CONTEXT, GstGLWrappedContext))
+#define GST_GL_WRAPPED_CONTEXT_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_CONTEXT, GstGLContextClass))
+#define GST_GL_IS_WRAPPED_CONTEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WRAPPED_CONTEXT))
+#define GST_GL_IS_WRAPPED_CONTEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WRAPPED_CONTEXT))
+#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WRAPPED_CONTEXT, GstGLWrappedContextClass))
+
 GQuark
 gst_gl_context_error_quark (void)
 {
@@ -142,6 +167,18 @@ gst_gl_context_class_init (GstGLContextClass * klass)
   G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize;
 }
 
+static void
+_init_debug (void)
+{
+  static volatile gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
+        "glcontext element");
+    g_once_init_leave (&_init, 1);
+  }
+}
+
 /**
  * gst_gl_context_new:
  * @display: a #GstGLDisplay
@@ -155,13 +192,8 @@ gst_gl_context_new (GstGLDisplay * display)
 {
   GstGLContext *context = NULL;
   const gchar *user_choice;
-  static volatile gsize _init = 0;
 
-  if (g_once_init_enter (&_init)) {
-    GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
-        "glcontext element");
-    g_once_init_leave (&_init, 1);
-  }
+  _init_debug ();
 
   user_choice = g_getenv ("GST_GL_PLATFORM");
   GST_INFO ("creating a context, user choice:%s", user_choice);
@@ -196,35 +228,77 @@ gst_gl_context_new (GstGLDisplay * display)
   return context;
 }
 
+/**
+ * gst_gl_context_new_wrapped:
+ * @display: a #GstGLDisplay
+ * @handle: the OpenGL context to wrap
+ * @context_type: a #GstGLPlatform specifying the type of context in @handle
+ * @available_apis: a #GstGLAPI containing the available OpenGL apis in @handle
+ *
+ * Wraps an existing OpenGL context into a #GstGLContext.  
+ *
+ * Returns: a #GstGLContext wrapping @handle
+ */
+GstGLContext *
+gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
+    GstGLPlatform context_type, GstGLAPI available_apis)
+{
+  GstGLContext *context;
+  GstGLWrappedContext *context_wrap = NULL;
+
+  _init_debug ();
+
+  context_wrap = g_object_new (GST_GL_TYPE_WRAPPED_CONTEXT, NULL);
+
+  if (!context_wrap) {
+    /* subclass returned a NULL context */
+    GST_ERROR ("Could not wrap existing context");
+
+    return NULL;
+  }
+
+  context = (GstGLContext *) context_wrap;
+
+  context->priv->display = gst_object_ref (display);
+  context_wrap->handle = handle;
+  context_wrap->platform = context_type;
+  context_wrap->available_apis = available_apis;
+
+  return context;
+}
+
 static void
 gst_gl_context_finalize (GObject * object)
 {
   GstGLContext *context = GST_GL_CONTEXT (object);
 
-  gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
-  gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
-
-  if (context->priv->alive) {
-    g_mutex_lock (&context->priv->render_lock);
-    GST_INFO ("send quit gl window loop");
-    gst_gl_window_quit (context->window);
-    while (context->priv->alive) {
-      g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
+  if (context->window) {
+    gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
+    gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
+
+    if (context->priv->alive) {
+      g_mutex_lock (&context->priv->render_lock);
+      GST_INFO ("send quit gl window loop");
+      gst_gl_window_quit (context->window);
+      while (context->priv->alive) {
+        g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
+      }
+      g_mutex_unlock (&context->priv->render_lock);
     }
-    g_mutex_unlock (&context->priv->render_lock);
-  }
 
-  gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
+    gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
+
+    if (context->priv->gl_thread) {
+      gpointer ret = g_thread_join (context->priv->gl_thread);
+      GST_INFO ("gl thread joined");
+      if (ret != NULL)
+        GST_ERROR ("gl thread returned a non-null pointer");
+      context->priv->gl_thread = NULL;
+    }
 
-  if (context->priv->gl_thread) {
-    gpointer ret = g_thread_join (context->priv->gl_thread);
-    GST_INFO ("gl thread joined");
-    if (ret != NULL)
-      GST_ERROR ("gl thread returned a non-null pointer");
-    context->priv->gl_thread = NULL;
+    gst_object_unref (context->window);
   }
 
-  gst_object_unref (context->window);
   gst_object_unref (context->priv->display);
 
   if (context->gl_vtable) {
@@ -310,6 +384,7 @@ gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
   GstGLContextClass *context_class;
 
   g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), NULL);
   context_class = GST_GL_CONTEXT_GET_CLASS (context);
   g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);
 
@@ -383,6 +458,8 @@ gst_gl_context_default_get_proc_address (GstGLContext * context,
 gboolean
 gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
 {
+  g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), NULL);
+
   /* we can't change the window while we are running */
   if (context->priv->alive)
     return FALSE;
@@ -413,6 +490,9 @@ gst_gl_context_get_window (GstGLContext * context)
 {
   g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
 
+  if (GST_GL_IS_WRAPPED_CONTEXT (context))
+    return NULL;
+
   _ensure_window (context);
 
   return gst_object_ref (context->window);
@@ -442,7 +522,7 @@ gst_gl_context_create (GstGLContext * context,
   gboolean alive = FALSE;
 
   g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE);
-
+  g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), FALSE);
   _ensure_window (context);
 
   g_mutex_lock (&context->priv->render_lock);
@@ -497,9 +577,6 @@ _create_context_gles2 (GstGLContext * context, gint * gl_major, gint * gl_minor,
   }
 #endif
 
-  _gst_gl_feature_check_ext_functions (context, 0, 0,
-      (const gchar *) gl->GetString (GL_EXTENSIONS));
-
   if (gl_major)
     *gl_major = 2;
   if (gl_minor)
@@ -546,9 +623,6 @@ _create_context_opengl (GstGLContext * context, gint * gl_major,
     return FALSE;
   }
 
-  _gst_gl_feature_check_ext_functions (context, maj, min,
-      (const gchar *) gl->GetString (GL_EXTENSIONS));
-
   if (gl_major)
     *gl_major = maj;
   if (gl_minor)
@@ -587,7 +661,7 @@ gst_gl_context_create_thread (GstGLContext * context)
   GstGLWindowClass *window_class;
   GstGLDisplay *display;
   GstGLFuncs *gl;
-  gint gl_major = 0;
+  gint gl_major = 0, gl_minor = 0;
   gboolean ret = FALSE;
   GstGLAPI compiled_api, user_api;
   gchar *api_string;
@@ -692,13 +766,16 @@ gst_gl_context_create_thread (GstGLContext * context)
 
   /* gl api specific code */
   if (!ret && USING_OPENGL (display))
-    ret = _create_context_opengl (context, &gl_major, NULL, error);
+    ret = _create_context_opengl (context, &gl_major, &gl_minor, error);
   if (!ret && USING_GLES2 (display))
-    ret = _create_context_gles2 (context, &gl_major, NULL, error);
+    ret = _create_context_gles2 (context, &gl_major, &gl_minor, error);
 
   if (!ret)
     goto failure;
 
+  _gst_gl_feature_check_ext_functions (context, gl_major, gl_minor,
+      (const gchar *) gl->GetString (GL_EXTENSIONS));
+
   context->priv->alive = TRUE;
 
   g_cond_signal (&context->priv->create_cond);
@@ -764,6 +841,26 @@ gst_gl_context_get_gl_context (GstGLContext * context)
 }
 
 /**
+ * gst_gl_context_get_gl_platform:
+ * @context: a #GstGLContext:
+ *
+ * Gets the OpenGL platform that used by @context.
+ *
+ * Returns: The platform specific backing OpenGL context
+ */
+GstGLPlatform
+gst_gl_context_get_gl_platform (GstGLContext * context)
+{
+  GstGLContextClass *context_class;
+
+  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), 0);
+  context_class = GST_GL_CONTEXT_GET_CLASS (context);
+  g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
+
+  return context_class->get_gl_platform (context);
+}
+
+/**
  * gst_gl_context_get_display:
  * @context: a #GstGLContext:
  *
@@ -811,6 +908,7 @@ gst_gl_context_thread_add (GstGLContext * context,
 
   g_return_if_fail (GST_GL_IS_CONTEXT (context));
   g_return_if_fail (func != NULL);
+  g_return_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context));
 
   rdata.context = context;
   rdata.data = data;
@@ -823,3 +921,65 @@ gst_gl_context_thread_add (GstGLContext * context,
 
   gst_object_unref (window);
 }
+
+
+static GstGLAPI
+gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
+{
+  GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+  return context_wrap->available_apis;
+}
+
+static guintptr
+gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
+{
+  GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+  return context_wrap->handle;
+}
+
+static GstGLPlatform
+gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
+{
+  GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+  return context_wrap->platform;
+}
+
+static gboolean
+gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
+{
+  g_assert_not_reached ();
+
+  return FALSE;
+}
+
+static void
+gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
+{
+  GstGLContextClass *context_class = (GstGLContextClass *) klass;
+
+  context_class->get_gl_context =
+      GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
+  context_class->get_gl_api =
+      GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
+  context_class->get_gl_platform =
+      GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
+  context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
+}
+
+static void
+gst_gl_wrapped_context_init (GstGLWrappedContext * context)
+{
+}
+
+/* Must be called in the gl thread */
+GstGLWrappedContext *
+gst_gl_wrapped_context_new (void)
+{
+  GstGLWrappedContext *context =
+      g_object_new (GST_GL_TYPE_WRAPPED_CONTEXT, NULL);
+
+  return context;
+}
index c4ee0bd..55db6cc 100644 (file)
@@ -47,6 +47,10 @@ GQuark gst_gl_context_error_quark (void);
  */
 typedef void (*GstGLContextThreadFunc) (GstGLContext * context, gpointer data);
 
+#define GST_GL_CONTEXT_TYPE_GLX "gst.gl.context.GLX"
+#define GST_GL_CONTEXT_TYPE_EGL "gst.gl.context.EGL"
+#define GST_GL_CONTEXT_TYPE_WGL "gst.gl.context.WGL"
+
 typedef enum
 {
   GST_GL_CONTEXT_ERROR_FAILED,
@@ -89,15 +93,16 @@ struct _GstGLContext {
 struct _GstGLContextClass {
   GObjectClass parent_class;
 
-  guintptr (*get_gl_context)     (GstGLContext *context);
-  GstGLAPI (*get_gl_api)         (GstGLContext *context);
-  gpointer (*get_proc_address)   (GstGLContext *context, const gchar *name);
-  gboolean (*activate)           (GstGLContext *context, gboolean activate);
-  gboolean (*choose_format)      (GstGLContext *context, GError **error);
-  gboolean (*create_context)     (GstGLContext *context, GstGLAPI gl_api,
-                                  GstGLContext *other_context, GError ** error);
-  void     (*destroy_context)    (GstGLContext *context);
-  void     (*swap_buffers)       (GstGLContext *context);
+  guintptr      (*get_gl_context)     (GstGLContext *context);
+  GstGLAPI      (*get_gl_api)         (GstGLContext *context);
+  GstGLPlatform (*get_gl_platform)    (GstGLContext *context);
+  gpointer      (*get_proc_address)   (GstGLContext *context, const gchar *name);
+  gboolean      (*activate)           (GstGLContext *context, gboolean activate);
+  gboolean      (*choose_format)      (GstGLContext *context, GError **error);
+  gboolean      (*create_context)     (GstGLContext *context, GstGLAPI gl_api,
+                                       GstGLContext *other_context, GError ** error);
+  void          (*destroy_context)    (GstGLContext *context);
+  void          (*swap_buffers)       (GstGLContext *context);
 
   /*< private >*/
   gpointer _reserved[GST_PADDING];
@@ -106,12 +111,16 @@ struct _GstGLContextClass {
 /* methods */
 
 GstGLContext * gst_gl_context_new  (GstGLDisplay *display);
+GstGLContext * gst_gl_context_new_wrapped (GstGLDisplay *display,
+                                           guintptr handle,
+                                           GstGLPlatform context_type,
+                                           GstGLAPI available_apis);
 
 gboolean      gst_gl_context_activate         (GstGLContext *context, gboolean activate);
 
 GstGLDisplay * gst_gl_context_get_display (GstGLContext *context);
 gpointer      gst_gl_context_get_proc_address (GstGLContext *context, const gchar *name);
-GstGLPlatform gst_gl_context_get_platform     (GstGLContext *context);
+GstGLPlatform gst_gl_context_get_gl_platform  (GstGLContext *context);
 GstGLAPI      gst_gl_context_get_gl_api       (GstGLContext *context);
 guintptr      gst_gl_context_get_gl_context   (GstGLContext *context);
 
index 2dba16d..bc3ea26 100644 (file)
@@ -43,6 +43,8 @@ static gboolean gst_gl_context_wgl_create_context (GstGLContext * context,
     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 GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext *
+    context);
 static gpointer gst_gl_context_wgl_get_proc_address (GstGLContext * context,
     const gchar * name);
 
@@ -66,6 +68,8 @@ gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
   context_class->get_proc_address =
       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_proc_address);
   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_api);
+  context_class->get_gl_platform =
+      GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform);
 }
 
 static void
@@ -88,7 +92,7 @@ gst_gl_context_wgl_create_context (GstGLContext * context,
 {
   GstGLWindow *window;
   GstGLContextWGL *context_wgl;
-  GstGLContextWGL *other_wgl = NULL;
+  HGLRC external_gl_context = NULL;
   HDC device;
 
   context_wgl = GST_GL_CONTEXT_WGL (context);
@@ -102,7 +106,7 @@ gst_gl_context_wgl_create_context (GstGLContext * context,
           "Cannot share context with a non-WGL context");
       goto failure;
     }
-    other_wgl = (GstGLContextWGL *) other_context;
+    external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context);
   }
 
   context_wgl->wgl_context = wglCreateContext (device);
@@ -120,8 +124,8 @@ 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)) {
+  if (external_gl_context) {
+    if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
       g_set_error (error, GST_GL_CONTEXT_ERROR,
           GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to share contexts 0x%x",
           (unsigned int) GetLastError ());
@@ -253,6 +257,12 @@ gst_gl_context_wgl_get_gl_api (GstGLContext * context)
   return GST_GL_API_OPENGL;
 }
 
+static GstGLPlatform
+gst_gl_context_wgl_get_gl_platform (GstGLContext * context)
+{
+  return GST_GL_PLATFORM_WGL;
+}
+
 static gpointer
 gst_gl_context_wgl_get_proc_address (GstGLContext * context, const gchar * name)
 {
index 2be004c..aeff736 100644 (file)
@@ -55,6 +55,8 @@ static void gst_gl_context_glx_destroy_context (GstGLContext * context);
 static gboolean gst_gl_context_glx_choose_format (GstGLContext *
     context, GError ** error);
 GstGLAPI gst_gl_context_glx_get_gl_api (GstGLContext * context);
+static GstGLPlatform gst_gl_context_glx_get_gl_platform (GstGLContext *
+    context);
 static gpointer gst_gl_context_glx_get_proc_address (GstGLContext * context,
     const gchar * name);
 
@@ -90,6 +92,8 @@ gst_gl_context_glx_class_init (GstGLContextGLXClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_glx_swap_buffers);
 
   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_api);
+  context_class->get_gl_platform =
+      GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform);
   context_class->get_proc_address =
       GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_proc_address);
 }
@@ -149,23 +153,17 @@ gst_gl_context_glx_create_context (GstGLContext * context,
   window_x11 = GST_GL_WINDOW_X11 (window);
 
   if (other_context) {
-    GstGLWindow *other_window;
-
-    if (!GST_GL_IS_CONTEXT_GLX (other_context)) {
+    if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) {
       g_set_error (error, GST_GL_CONTEXT_ERROR,
           GST_GL_CONTEXT_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);
   }
 
+  device = (Display *) gst_gl_window_get_display (window);
   glx_exts = glXQueryExtensionsString (device, DefaultScreen (device));
 
   create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts);
@@ -408,6 +406,12 @@ gst_gl_context_glx_get_gl_api (GstGLContext * context)
   return context_glx->priv->context_api;
 }
 
+static GstGLPlatform
+gst_gl_context_glx_get_gl_platform (GstGLContext * context)
+{
+  return GST_GL_PLATFORM_GLX;
+}
+
 static gpointer
 gst_gl_context_glx_get_proc_address (GstGLContext * context, const gchar * name)
 {
index 2139b4b..3425e03 100644 (file)
@@ -117,7 +117,8 @@ deinit (gpointer data)
   gl->DeleteTextures (1, &tex);;
   gst_object_unref (fbo);
 #if GST_GL_HAVE_GLES2
-  gst_object_unref (shader);
+  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+    gst_object_unref (shader);
 #endif
 }
 
@@ -281,6 +282,66 @@ GST_START_TEST (test_share)
 
 GST_END_TEST;
 
+GST_START_TEST (test_wrapped_context)
+{
+  GstGLContext *context, *other_context, *wrapped_context;
+  GstGLWindow *window, *other_window;
+  GError *error = NULL;
+  gint i = 0;
+  guintptr handle;
+  GstGLPlatform platform;
+  GstGLAPI apis;
+
+  display = gst_gl_display_new ();
+  context = gst_gl_context_new (display);
+
+  window = gst_gl_window_new (display);
+  gst_gl_context_set_window (context, window);
+
+  gst_gl_context_create (context, 0, &error);
+
+  fail_if (error != NULL, "Error creating master context %s\n",
+      error ? error->message : "Unknown Error");
+
+  handle = gst_gl_context_get_gl_context (context);
+  platform = gst_gl_context_get_gl_platform (context);
+  apis = gst_gl_context_get_gl_api (context);
+
+  wrapped_context =
+      gst_gl_context_new_wrapped (display, handle, platform, apis);
+
+  other_context = gst_gl_context_new (display);
+  other_window = gst_gl_window_new (display);
+  gst_gl_context_set_window (other_context, other_window);
+
+  gst_gl_context_create (other_context, wrapped_context, &error);
+
+  fail_if (error != NULL, "Error creating secondary context %s\n",
+      error ? error->message : "Unknown Error");
+
+  /* make the window visible */
+  gst_gl_window_draw (window, 320, 240);
+
+  gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), context);
+
+  while (i < 1000) {
+    gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (draw_tex),
+        context);
+    gst_gl_window_send_message (window, GST_GL_WINDOW_CB (draw_render),
+        context);
+    i++;
+  }
+
+  gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), context);
+
+  gst_object_unref (window);
+  gst_object_unref (other_window);
+  gst_object_unref (other_context);
+  gst_object_unref (context);
+}
+
+GST_END_TEST;
+
 
 Suite *
 gst_gl_memory_suite (void)
@@ -291,6 +352,7 @@ gst_gl_memory_suite (void)
   suite_add_tcase (s, tc_chain);
   tcase_add_checked_fixture (tc_chain, setup, teardown);
   tcase_add_test (tc_chain, test_share);
+  tcase_add_test (tc_chain, test_wrapped_context);
 
   return s;
 }