[701/906] display: move context creation into window
authorMatthew Waters <ystreet00@gmail.com>
Wed, 12 Jun 2013 13:17:30 +0000 (23:17 +1000)
committerMatthew Waters <ystreet00@gmail.com>
Sat, 15 Mar 2014 17:36:55 +0000 (18:36 +0100)
23 files changed:
gst-libs/gst/gl/gstgldisplay.c
gst-libs/gst/gl/gstgldisplay.h
gst-libs/gst/gl/gstgldownload.c
gst-libs/gst/gl/gstglfeature.c
gst-libs/gst/gl/gstglfilter.c
gst-libs/gst/gl/gstglmemory.c
gst-libs/gst/gl/gstglmixer.c
gst-libs/gst/gl/gstglupload.c
gst-libs/gst/gl/gstglutils.c
gst-libs/gst/gl/gstglutils.h
gst-libs/gst/gl/gstglwindow.c
gst-libs/gst/gl/gstglwindow.h
gst/gl/effects/gstgleffectidentity.c
gst/gl/effects/gstgleffectmirror.c
gst/gl/effects/gstgleffectsqueeze.c
gst/gl/gltestsrc.c
gst/gl/gstglbumper.c
gst/gl/gstgleffects.c
gst/gl/gstglfiltercube.c
gst/gl/gstglimagesink.c
gst/gl/gstglimagesink.h
gst/gl/gstgloverlay.c
gst/gl/gstgltestsrc.c

index 6566b75..ef406ff 100644 (file)
@@ -62,9 +62,7 @@ void gst_gl_display_thread_run_generic (GstGLDisplay * display);
 
 struct _GstGLDisplayPrivate
 {
-  /* conditions */
-  GCond cond_create_context;
-  GCond cond_destroy_context;
+  GstGLWindow *window;
 
   /* generic gl code */
   GstGLDisplayThreadFunc generic_callback;
@@ -91,13 +89,8 @@ gst_gl_display_init (GstGLDisplay * display)
   /* thread safe */
   g_mutex_init (&display->mutex);
 
-  g_cond_init (&display->priv->cond_create_context);
-  g_cond_init (&display->priv->cond_destroy_context);
-
   display->gl_vtable = g_slice_alloc0 (sizeof (GstGLFuncs));
 
-  display->gl_window = gst_gl_window_new ();
-
   gst_gl_memory_init ();
 }
 
@@ -106,39 +99,8 @@ gst_gl_display_finalize (GObject * object)
 {
   GstGLDisplay *display = GST_GL_DISPLAY (object);
 
-  if (display->gl_window) {
-    gst_gl_display_lock (display);
-
-    gst_gl_window_set_resize_callback (display->gl_window, NULL, NULL);
-    gst_gl_window_set_draw_callback (display->gl_window, NULL, NULL);
-    gst_gl_window_set_close_callback (display->gl_window, NULL, NULL);
-
-    if (display->context_created) {
-      GST_INFO ("send quit gl window loop");
-      gst_gl_window_quit (display->gl_window,
-          GST_GL_WINDOW_CB (gst_gl_display_thread_destroy_context), display);
-
-      GST_INFO ("quit sent to gl window loop");
-
-      g_cond_wait (&display->priv->cond_destroy_context, &display->mutex);
-      GST_INFO ("quit received from gl window");
-    }
-    gst_gl_display_unlock (display);
-  }
-
-  if (display->gl_thread) {
-    gpointer ret = g_thread_join (display->gl_thread);
-    GST_INFO ("gl thread joined");
-    if (ret != NULL)
-      GST_ERROR ("gl thread returned a not null pointer");
-    display->gl_thread = NULL;
-  }
-
   g_mutex_clear (&display->mutex);
 
-  g_cond_clear (&display->priv->cond_destroy_context);
-  g_cond_clear (&display->priv->cond_create_context);
-
   if (display->error_message) {
     g_free (display->error_message);
     display->error_message = NULL;
@@ -148,271 +110,13 @@ gst_gl_display_finalize (GObject * object)
     g_slice_free (GstGLFuncs, display->gl_vtable);
     display->gl_vtable = NULL;
   }
-}
-
-static gboolean
-_create_context_gles2 (GstGLDisplay * display, gint * gl_major, gint * gl_minor)
-{
-  const GstGLFuncs *gl;
-  GLenum gl_err = GL_NO_ERROR;
-
-  gl = display->gl_vtable;
-
-  GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
-  GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
-      gl->GetString (GL_SHADING_LANGUAGE_VERSION));
-  GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
-  GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
-
-  gl_err = gl->GetError ();
-  if (gl_err != GL_NO_ERROR) {
-    gst_gl_display_set_error (display, "glGetString error: 0x%x", gl_err);
-    return FALSE;
-  }
-#if GST_GL_HAVE_GLES2
-  if (!GL_ES_VERSION_2_0) {
-    gst_gl_display_set_error (display, "OpenGL|ES >= 2.0 is required");
-    return FALSE;
-  }
-#endif
-
-  _gst_gl_feature_check_ext_functions (display, 0, 0,
-      (const gchar *) gl->GetString (GL_EXTENSIONS));
-
-  if (gl_major)
-    *gl_major = 2;
-  if (gl_minor)
-    *gl_minor = 0;
-
-  return TRUE;
-}
-
-gboolean
-_create_context_opengl (GstGLDisplay * display, gint * gl_major,
-    gint * gl_minor)
-{
-  const GstGLFuncs *gl;
-  guint maj, min;
-  GLenum gl_err = GL_NO_ERROR;
-  GString *opengl_version = NULL;
-
-  gl = display->gl_vtable;
-
-  GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
-  GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
-      gl->GetString (GL_SHADING_LANGUAGE_VERSION));
-  GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
-  GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
-
-  gl_err = gl->GetError ();
-  if (gl_err != GL_NO_ERROR) {
-    gst_gl_display_set_error (display, "glGetString error: 0x%x", gl_err);
-    return FALSE;
-  }
-  opengl_version =
-      g_string_truncate (g_string_new ((gchar *) gl->GetString (GL_VERSION)),
-      3);
-
-  sscanf (opengl_version->str, "%d.%d", &maj, &min);
-
-  g_string_free (opengl_version, TRUE);
-
-  /* OpenGL > 1.2.0 */
-  if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
-    gst_gl_display_set_error (display, "OpenGL >= 1.2.0 required, found %u.%u",
-        maj, min);
-    return FALSE;
-  }
-
-  _gst_gl_feature_check_ext_functions (display, maj, min,
-      (const gchar *) gl->GetString (GL_EXTENSIONS));
-
-  if (gl_major)
-    *gl_major = maj;
-  if (gl_minor)
-    *gl_minor = min;
-
-  return TRUE;
-}
-
-GstGLAPI
-_compiled_api (void)
-{
-  GstGLAPI ret = GST_GL_API_NONE;
-
-#if GST_GL_HAVE_OPENGL
-  ret |= GST_GL_API_OPENGL;
-#endif
-#if GST_GL_HAVE_GLES2
-  ret |= GST_GL_API_GLES2;
-#endif
-
-  return ret;
-}
-
-GstGLAPI
-_parse_gl_api (const gchar * apis_s)
-{
-  GstGLAPI ret = GST_GL_API_NONE;
-  gchar *apis = (gchar *) apis_s;
-
-  while (apis) {
-    if (apis[0] == '\0') {
-      break;
-    } else if (apis[0] == ' ' || apis[0] == ',') {
-      apis = &apis[1];
-    } else if (g_strstr_len (apis, 7, "opengl3")) {
-      ret |= GST_GL_API_OPENGL3;
-      apis = &apis[7];
-    } else if (g_strstr_len (apis, 6, "opengl")) {
-      ret |= GST_GL_API_OPENGL;
-      apis = &apis[6];
-    } else if (g_strstr_len (apis, 5, "gles1")) {
-      ret |= GST_GL_API_GLES;
-      apis = &apis[5];
-    } else if (g_strstr_len (apis, 5, "gles2")) {
-      ret |= GST_GL_API_GLES2;
-      apis = &apis[5];
-    } else if (g_strstr_len (apis, 5, "gles3")) {
-      ret |= GST_GL_API_GLES3;
-      apis = &apis[5];
-    } else {
-      break;
-    }
-  }
-
-  if (ret == GST_GL_API_NONE)
-    ret = GST_GL_API_ANY;
-
-  return ret;
-}
-
-gpointer
-gst_gl_display_thread_create_context (GstGLDisplay * display)
-{
-  GstGLFuncs *gl;
-  gint gl_major = 0;
-  gboolean ret = FALSE;
-  GError *error = NULL;
-  GstGLAPI compiled_api, user_api;
-  gchar *api_string;
-  gchar *compiled_api_s;
-  gchar *user_api_string;
-  const gchar *user_choice;
-
-  gst_gl_display_lock (display);
-
-  gl = display->gl_vtable;
-  compiled_api = _compiled_api ();
-
-  if (!display->gl_window) {
-    gst_gl_display_set_error (display, "Failed to create opengl window");
-    goto failure;
-  }
-
-  user_choice = g_getenv ("GST_GL_API");
-
-  user_api = _parse_gl_api (user_choice);
-  user_api_string = gst_gl_api_string (user_api);
-
-  compiled_api_s = gst_gl_api_string (compiled_api);
-
-  GST_INFO ("Attempting to create opengl context. user chosen api(s):%s, "
-      "compiled api support:%s", user_api_string, compiled_api_s);
-
-  if (!gst_gl_window_create_context (display->gl_window,
-          compiled_api & user_api, display->external_gl_context, &error)) {
-    gst_gl_display_set_error (display,
-        error ? error->message : "Failed to create gl window");
-    g_free (compiled_api_s);
-    g_free (user_api_string);
-    goto failure;
-  }
-  GST_INFO ("window created context");
-
-  display->gl_api = gst_gl_window_get_gl_api (display->gl_window);
-  g_assert (display->gl_api != GST_GL_API_NONE
-      && display->gl_api != GST_GL_API_ANY);
-
-  api_string = gst_gl_api_string (display->gl_api);
-  GST_INFO ("available GL APIs: %s", api_string);
-
-  if (((compiled_api & display->gl_api) & user_api) == GST_GL_API_NONE) {
-    gst_gl_display_set_error (display, "failed to create context, window "
-        "could not provide correct api. user:%s, compiled:%s, window:%s",
-        user_api_string, compiled_api_s, api_string);
-    g_free (api_string);
-    g_free (compiled_api_s);
-    g_free (user_api_string);
-    goto failure;
-  }
-
-  g_free (api_string);
-  g_free (compiled_api_s);
-  g_free (user_api_string);
-
-  gl->GetError =
-      gst_gl_window_get_proc_address (display->gl_window, "glGetError");
-  gl->GetString =
-      gst_gl_window_get_proc_address (display->gl_window, "glGetString");
-
-  if (!gl->GetError || !gl->GetString) {
-    gst_gl_display_set_error (display,
-        "could not GetProcAddress core opengl functions");
-    goto failure;
-  }
-
-  /* gl api specific code */
-  if (!ret && USING_OPENGL (display))
-    ret = _create_context_opengl (display, &gl_major, NULL);
-  if (!ret && USING_GLES2 (display))
-    ret = _create_context_gles2 (display, &gl_major, NULL);
-
-  if (!ret || !gl_major) {
-    GST_WARNING ("GL api specific initialization failed");
-    goto failure;
-  }
-
-  g_cond_signal (&display->priv->cond_create_context);
-
-  display->isAlive = TRUE;
-  gst_gl_display_unlock (display);
-
-  gst_gl_window_run (display->gl_window);
-
-  GST_INFO ("loop exited\n");
-
-  gst_gl_display_lock (display);
-
-  display->isAlive = FALSE;
-
-  g_object_unref (G_OBJECT (display->gl_window));
 
-  display->gl_window = NULL;
-
-  g_cond_signal (&display->priv->cond_destroy_context);
-
-  gst_gl_display_unlock (display);
-
-  return NULL;
-
-failure:
-  {
-    if (display->gl_window) {
-      g_object_unref (display->gl_window);
-      display->gl_window = NULL;
-    }
-
-    g_cond_signal (&display->priv->cond_create_context);
-    gst_gl_display_unlock (display);
-    return NULL;
+  if (display->priv->window) {
+    gst_object_unref (display->priv->window);
+    display->priv->window = NULL;
   }
-}
 
-void
-gst_gl_display_thread_destroy_context (GstGLDisplay * display)
-{
-  GST_INFO ("Context destroyed");
+  G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object);
 }
 
 //------------------------------------------------------------
@@ -434,8 +138,6 @@ gst_gl_display_set_error (GstGLDisplay * display, const char *format, ...)
   va_end (args);
 
   GST_WARNING ("%s", display->error_message);
-
-  display->isAlive = FALSE;
 }
 
 void
@@ -470,97 +172,106 @@ gst_gl_display_new (void)
   return g_object_new (GST_GL_TYPE_DISPLAY, NULL);
 }
 
-/* Create an opengl context (one context for one GstGLDisplay) */
-gboolean
-gst_gl_display_create_context (GstGLDisplay * display,
-    gulong external_gl_context)
-{
-  gboolean isAlive = FALSE;
-
-  gst_gl_display_lock (display);
-
-  if (!display->context_created) {
-    display->external_gl_context = external_gl_context;
-
-    display->gl_thread = g_thread_new ("gstglcontext",
-        (GThreadFunc) gst_gl_display_thread_create_context, display);
-
-    g_cond_wait (&display->priv->cond_create_context, &display->mutex);
-
-    display->context_created = TRUE;
-
-    GST_INFO ("gl thread created");
-  }
-
-  isAlive = display->isAlive;
-
-  gst_gl_display_unlock (display);
-
-  return isAlive;
-}
-
 void
 gst_gl_display_thread_add (GstGLDisplay * display,
     GstGLDisplayThreadFunc func, gpointer data)
 {
+  g_return_if_fail (GST_IS_GL_DISPLAY (display));
+  g_return_if_fail (GST_GL_IS_WINDOW (display->priv->window));
+  g_return_if_fail (func != NULL);
+
   gst_gl_display_lock (display);
+
   display->priv->data = data;
   display->priv->generic_callback = func;
-  gst_gl_window_send_message (display->gl_window,
+
+  gst_gl_window_send_message (display->priv->window,
       GST_GL_WINDOW_CB (gst_gl_display_thread_run_generic), display);
+
   gst_gl_display_unlock (display);
 }
 
 guintptr
 gst_gl_display_get_internal_gl_context (GstGLDisplay * display)
 {
-  gulong external_gl_context = 0;
-  gst_gl_display_lock (display);
-  external_gl_context = gst_gl_window_get_gl_context (display->gl_window);
-  gst_gl_display_unlock (display);
-  return external_gl_context;
+  g_return_val_if_fail (GST_IS_GL_DISPLAY (display), 0);
+  g_return_val_if_fail (GST_GL_IS_WINDOW (display->priv->window), 0);
+
+  return gst_gl_window_get_gl_context (display->priv->window);
 }
 
 void
 gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activate)
 {
+  g_return_if_fail (GST_IS_GL_DISPLAY (display));
+  g_return_if_fail (GST_GL_IS_WINDOW (display->priv->window));
+
   if (!activate)
     gst_gl_display_lock (display);
-  gst_gl_window_activate (display->gl_window, activate);
+
+  gst_gl_window_activate (display->priv->window, activate);
+
   if (activate)
     gst_gl_display_unlock (display);
 }
 
 GstGLAPI
-gst_gl_display_get_gl_api_unlocked (GstGLDisplay * display)
+gst_gl_display_get_gl_api (GstGLDisplay * display)
 {
+  g_return_val_if_fail (GST_IS_GL_DISPLAY (display), GST_GL_API_NONE);
+
   return display->gl_api;
 }
 
-GstGLAPI
-gst_gl_display_get_gl_api (GstGLDisplay * display)
+gpointer
+gst_gl_display_get_gl_vtable (GstGLDisplay * display)
 {
-  GstGLAPI api;
+  gpointer gl;
+
+  g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
+
+  gl = display->gl_vtable;
+
+  return gl;
+}
+
+void
+gst_gl_display_set_window (GstGLDisplay * display, GstGLWindow * window)
+{
+  g_return_if_fail (GST_IS_GL_DISPLAY (display));
+  g_return_if_fail (GST_GL_IS_WINDOW (window));
 
   gst_gl_display_lock (display);
-  api = gst_gl_display_get_gl_api_unlocked (display);
-  gst_gl_display_unlock (display);
 
-  return api;
+  if (display->priv->window)
+    gst_object_unref (display->priv->window);
+
+  display->priv->window = gst_object_ref (window);
+
+  gst_gl_display_unlock (display);
 }
 
-gpointer
-gst_gl_display_get_gl_vtable (GstGLDisplay * display)
+GstGLWindow *
+gst_gl_display_get_window (GstGLDisplay * display)
 {
-  gpointer gl;
+  GstGLWindow *window;
+
+  g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
 
   gst_gl_display_lock (display);
-  gl = display->gl_vtable;
+
+  window =
+      display->priv->window ? gst_object_ref (display->priv->window) : NULL;
+
   gst_gl_display_unlock (display);
 
-  return gl;
+  return window;
 }
 
-//------------------------------------------------------------
-//------------------------ END PUBLIC ------------------------
-//------------------------------------------------------------
+GstGLWindow *
+gst_gl_display_get_window_unlocked (GstGLDisplay * display)
+{
+  g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
+
+  return display->priv->window ? gst_object_ref (display->priv->window) : NULL;
+}
index 6ea7710..5cdb544 100644 (file)
@@ -28,6 +28,7 @@
 #include <gst/video/video.h>
 
 typedef struct _GstGLShader GstGLShader;
+typedef struct _GstGLWindow GstGLWindow;
 
 #include "gstglwindow.h"
 #include "gstglshader.h"
@@ -89,12 +90,6 @@ struct _GstGLDisplay
   /* thread safe */
   GMutex         mutex;
 
-  /* gl context */
-  GThread       *gl_thread;
-  GstGLWindow   *gl_window;
-  gboolean       isAlive;
-  gboolean       context_created;
-
   /* gl API we are using */
   GstGLAPI       gl_api;
   /* foreign gl context */
@@ -115,9 +110,6 @@ struct _GstGLDisplayClass
 
 GstGLDisplay *gst_gl_display_new (void);
 
-gboolean gst_gl_display_create_context (GstGLDisplay * display,
-    gulong external_gl_context);
-
 void gst_gl_display_thread_add (GstGLDisplay * display,
     GstGLDisplayThreadFunc func, gpointer data);
 
@@ -126,15 +118,17 @@ void gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activa
 
 /* Must be called inside a lock/unlock on display, or within the glthread */
 void gst_gl_display_set_error (GstGLDisplay * display, const char * format, ...);
-gboolean gst_gl_display_check_framebuffer_status (GstGLDisplay * display);
 
 void gst_gl_display_lock (GstGLDisplay * display);
 void gst_gl_display_unlock (GstGLDisplay * display);
 GstGLAPI gst_gl_display_get_gl_api (GstGLDisplay * display);
-GstGLAPI gst_gl_display_get_gl_api_unlocked (GstGLDisplay * display);
 
 gpointer gst_gl_display_get_gl_vtable (GstGLDisplay * display);
 
+void gst_gl_display_set_window (GstGLDisplay * display, GstGLWindow * window);
+GstGLWindow * gst_gl_display_get_window (GstGLDisplay * display);
+GstGLWindow * gst_gl_display_get_window_unlocked (GstGLDisplay * display);
+
 G_END_DECLS
 
 #endif /* __GST_GL_H__ */
index a9cdec2..cce9ee3 100644 (file)
  * calling thread.
  */
 
-#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
-#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
-#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
-#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
-#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
+#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
+#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
+#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
 
 static void _do_download (GstGLDisplay * display, GstGLDownload * download);
 static void _init_download (GstGLDisplay * display, GstGLDownload * download);
index 641cc38..72c347c 100644 (file)
@@ -150,6 +150,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
   const char *suffix = NULL;
   int func_num;
   GstGLFuncs *gst_gl = display->gl_vtable;
+  GstGLWindow *window = NULL;
 
   /* First check whether the functions should be directly provided by
      GL */
@@ -172,6 +173,9 @@ _gst_gl_feature_check (GstGLDisplay * display,
   if (suffix == NULL)
     goto error;
 
+  window = gst_gl_display_get_window (display);
+  g_assert (window);
+
   /* Try to get all of the entry points */
   for (func_num = 0; data->functions[func_num].name; func_num++) {
     void *func;
@@ -183,8 +187,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
         suffix, NULL);
     GST_TRACE ("%s should %sbe in core", full_function_name,
         in_core ? "" : "not ");
-    func =
-        gst_gl_window_get_proc_address (display->gl_window, full_function_name);
+    func = gst_gl_window_get_proc_address (window, full_function_name);
 
     if (func == NULL && in_core) {
       GST_TRACE ("%s was not found in core, trying the extension version",
@@ -196,8 +199,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
         g_free (full_function_name);
         full_function_name = g_strconcat ("gl", data->functions[func_num].name,
             suffix, NULL);
-        func = gst_gl_window_get_proc_address (display->gl_window,
-            full_function_name);
+        func = gst_gl_window_get_proc_address (window, full_function_name);
       }
     }
 
@@ -212,6 +214,7 @@ _gst_gl_feature_check (GstGLDisplay * display,
   }
 
   g_free (full_function_name);
+  gst_object_unref (window);
 
   return TRUE;
 
@@ -230,6 +233,9 @@ error:
     g_free (full_function_name);
   }
 
+  if (window)
+    gst_object_unref (window);
+
   return FALSE;
 }
 
index 72d156f..099be08 100644 (file)
@@ -253,11 +253,18 @@ gst_gl_filter_start (GstBaseTransform * bt)
     filter->display =
         g_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value)));
   else {
+    GstGLWindow *window;
+    GError *error = NULL;
+
     GST_INFO ("Creating GstGLDisplay");
     filter->display = gst_gl_display_new ();
-    if (!gst_gl_display_create_context (filter->display, 0)) {
+    window = gst_gl_window_new (filter->display);
+    gst_gl_display_set_window (filter->display, window);
+    g_object_unref (window);
+
+    if (!gst_gl_window_create_context (window, 0, &error)) {
       GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND,
-          GST_GL_DISPLAY_ERR_MSG (filter->display), (NULL));
+          ("%s", error->message), (NULL));
       return FALSE;
     }
   }
@@ -727,9 +734,10 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps,
   if (filter_class->display_init_cb != NULL) {
     gst_gl_display_thread_add (filter->display, gst_gl_filter_start_gl, filter);
   }
-
+#if 0
   if (!filter->display->isAlive)
     goto error;
+#endif
 
   if (filter_class->onInitFBO) {
     if (!filter_class->onInitFBO (filter))
index 424e4bd..aac56c3 100644 (file)
@@ -25,6 +25,7 @@
 #include <gst/video/video.h>
 
 #include "gstglmemory.h"
+#include "gstglutils.h"
 
 /**
  * SECTION:gstglmemory
index 1e4b99c..4104d58 100644 (file)
@@ -935,11 +935,18 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate)
       mix->display =
           g_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value)));
     else {
+      GstGLWindow *window;
+      GError *error = NULL;
+
       GST_INFO ("Creating GstGLDisplay");
       mix->display = gst_gl_display_new ();
-      if (!gst_gl_display_create_context (mix->display, 0)) {
+      window = gst_gl_window_new (mix->display);
+      gst_gl_display_set_window (mix->display, window);
+      g_object_unref (window);
+
+      if (!gst_gl_window_create_context (window, 0, &error)) {
         GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND,
-            GST_GL_DISPLAY_ERR_MSG (mix->display), (NULL));
+            ("%s", error->message), (NULL));
         return FALSE;
       }
     }
index 18cb369..00d5a99 100644 (file)
  * calling thread.
  */
 
-#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
-#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
-#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
-#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
-#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
+#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
+#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
+#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
 
 static void _do_upload (GstGLDisplay * display, GstGLUpload * upload);
 static void _do_upload_fill (GstGLDisplay * display, GstGLUpload * upload);
index 3e29c96..9a92fa8 100644 (file)
@@ -234,18 +234,24 @@ void
 gst_gl_display_gen_texture (GstGLDisplay * display, GLuint * pTexture,
     GstVideoFormat v_format, GLint width, GLint height)
 {
+  GstGLWindow *window;
+
   gst_gl_display_lock (display);
 
-  if (display->isAlive) {
+  window = gst_gl_display_get_window_unlocked (display);
+
+  if (gst_gl_window_is_running (window)) {
     gen_texture_width = width;
     gen_texture_height = height;
     gen_texture_video_format = v_format;
-    gst_gl_window_send_message (display->gl_window,
+    gst_gl_window_send_message (window,
         GST_GL_WINDOW_CB (gst_gl_display_gen_texture_window_cb), display);
     *pTexture = gen_texture;
   } else
     *pTexture = 0;
 
+  gst_object_unref (window);
+
   gst_gl_display_unlock (display);
 }
 
@@ -263,21 +269,26 @@ gboolean
 gst_gl_display_gen_fbo (GstGLDisplay * display, gint width, gint height,
     GLuint * fbo, GLuint * depthbuffer)
 {
-  gboolean isAlive = FALSE;
+  gboolean alive = FALSE;
+  GstGLWindow *window;
 
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+
+  if (gst_gl_window_is_running (window)) {
     gen_fbo_width = width;
     gen_fbo_height = height;
-    gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_gen_fbo),
-        display);
+    gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_gen_fbo), display);
     *fbo = generated_fbo;
     *depthbuffer = generated_depth_buffer;
   }
-  isAlive = display->isAlive;
+  alive = gst_gl_window_is_running (window);
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 
-  return isAlive;
+  return alive;
 }
 
 
@@ -297,10 +308,13 @@ gst_gl_display_use_fbo (GstGLDisplay * display, gint texture_fbo_width,
     gdouble proj_param2, gdouble proj_param3, gdouble proj_param4,
     GstGLDisplayProjection projection, gpointer * stuff)
 {
-  gboolean isAlive;
+  gboolean alive;
+  GstGLWindow *window;
 
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+  if (gst_gl_window_is_running (window)) {
     use_fbo = fbo;
     use_depth_buffer = depth_buffer;
     use_fbo_texture = texture_fbo;
@@ -316,13 +330,14 @@ gst_gl_display_use_fbo (GstGLDisplay * display, gint texture_fbo_width,
     input_texture_width = input_tex_width;
     input_texture_height = input_tex_height;
     input_texture = input_tex;
-    gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_use_fbo),
-        display);
+    gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_use_fbo), display);
   }
-  isAlive = display->isAlive;
+  alive = gst_gl_window_is_running (window);
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 
-  return isAlive;
+  return alive;
 }
 
 gboolean
@@ -330,10 +345,13 @@ gst_gl_display_use_fbo_v2 (GstGLDisplay * display, gint texture_fbo_width,
     gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
     GLuint texture_fbo, GLCB_V2 cb, gpointer * stuff)
 {
-  gboolean isAlive;
+  gboolean alive;
+  GstGLWindow *window;
 
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+  if (gst_gl_window_is_running (window)) {
     use_fbo = fbo;
     use_depth_buffer = depth_buffer;
     use_fbo_texture = texture_fbo;
@@ -341,26 +359,33 @@ gst_gl_display_use_fbo_v2 (GstGLDisplay * display, gint texture_fbo_width,
     use_fbo_height = texture_fbo_height;
     use_fbo_scene_cb_v2 = cb;
     use_fbo_stuff = stuff;
-    gst_gl_window_send_message (display->gl_window,
+    gst_gl_window_send_message (window,
         GST_GL_WINDOW_CB (_use_fbo_v2), display);
   }
-  isAlive = display->isAlive;
+  alive = gst_gl_window_is_running (window);
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 
-  return isAlive;
+  return alive;
 }
 
 /* Called by gltestsrc and glfilter */
 void
 gst_gl_display_del_fbo (GstGLDisplay * display, GLuint fbo, GLuint depth_buffer)
 {
+  GstGLWindow *window;
+
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+  if (gst_gl_window_is_running (window)) {
     del_fbo = fbo;
     del_depth_buffer = depth_buffer;
-    gst_gl_window_send_message (display->gl_window, GST_GL_WINDOW_CB (_del_fbo),
-        display);
+    gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_del_fbo), display);
   }
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 }
 
@@ -371,13 +396,16 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
     const gchar * shader_vertex_source,
     const gchar * shader_fragment_source, GstGLShader ** shader)
 {
-  gboolean isAlive;
+  gboolean alive;
+  GstGLWindow *window;
 
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+  if (gst_gl_window_is_running (window)) {
     gen_shader_vertex_source = shader_vertex_source;
     gen_shader_fragment_source = shader_fragment_source;
-    gst_gl_window_send_message (display->gl_window,
+    gst_gl_window_send_message (window,
         GST_GL_WINDOW_CB (_gen_shader), display);
     if (shader)
       *shader = gen_shader;
@@ -385,10 +413,12 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
     gen_shader_vertex_source = NULL;
     gen_shader_fragment_source = NULL;
   }
-  isAlive = display->isAlive;
+  alive = gst_gl_window_is_running (window);
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 
-  return isAlive;
+  return alive;
 }
 
 
@@ -396,12 +426,18 @@ gst_gl_display_gen_shader (GstGLDisplay * display,
 void
 gst_gl_display_del_shader (GstGLDisplay * display, GstGLShader * shader)
 {
+  GstGLWindow *window;
+
   gst_gl_display_lock (display);
-  if (display->isAlive) {
+
+  window = gst_gl_display_get_window_unlocked (display);
+  if (gst_gl_window_is_running (window)) {
     del_shader = shader;
-    gst_gl_window_send_message (display->gl_window,
+    gst_gl_window_send_message (window,
         GST_GL_WINDOW_CB (_del_shader), display);
   }
+
+  gst_object_unref (window);
   gst_gl_display_unlock (display);
 }
 
index 69a02b7..bdff171 100644 (file)
@@ -99,4 +99,6 @@ gboolean gst_gl_display_gen_shader (GstGLDisplay * display,
     const gchar * shader_fragment_source, GstGLShader ** shader);
 void gst_gl_display_del_shader (GstGLDisplay * display, GstGLShader * shader);
 
+gboolean gst_gl_display_check_framebuffer_status (GstGLDisplay * display);
+
 #endif /* __GST_GL_UTILS_H__ */
index 66cfa02..40355fe 100644 (file)
@@ -23,6 +23,7 @@
 #endif
 
 #include <gmodule.h>
+#include <stdio.h>
 
 #include "gstglwindow.h"
 
 #include "wayland/gstglwindow_wayland_egl.h"
 #endif
 
+#include "gstglfeature.h"
+
+#define USING_OPENGL(display) (display->gl_api & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (display->gl_api & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (display->gl_api & GST_GL_API_GLES)
+#define USING_GLES2(display) (display->gl_api & GST_GL_API_GLES2)
+#define USING_GLES3(display) (display->gl_api & GST_GL_API_GLES3)
+
 #define GST_CAT_DEFAULT gst_gl_window_debug
 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
 
 #define gst_gl_window_parent_class parent_class
 G_DEFINE_ABSTRACT_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT);
 
+#define GST_GL_WINDOW_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate))
+
+struct _GstGLWindowPrivate
+{
+  GstGLDisplay *display;
+
+  GThread *gl_thread;
+
+  /* conditions */
+  GMutex render_lock;
+  GCond cond_create_context;
+  GCond cond_destroy_context;
+
+  gboolean context_created;
+  gboolean alive;
+
+  guintptr external_gl_context;
+  GstGLAPI gl_api;
+  GError **error;
+};
+
+static gpointer _gst_gl_window_thread_create_context (GstGLWindow * window);
+static void gst_gl_window_finalize (GObject * object);
+
 GQuark
 gst_gl_window_error_quark (void)
 {
@@ -54,19 +88,30 @@ gst_gl_window_error_quark (void)
 static void
 gst_gl_window_init (GstGLWindow * window)
 {
+  window->priv = GST_GL_WINDOW_GET_PRIVATE (window);
+
   g_mutex_init (&window->lock);
   window->need_lock = TRUE;
+
+  g_mutex_init (&window->priv->render_lock);
+  g_cond_init (&window->priv->cond_create_context);
+  g_cond_init (&window->priv->cond_destroy_context);
+  window->priv->context_created = FALSE;
 }
 
 static void
 gst_gl_window_class_init (GstGLWindowClass * klass)
 {
+  g_type_class_add_private (klass, sizeof (GstGLWindowPrivate));
+
   klass->get_proc_address =
       GST_DEBUG_FUNCPTR (gst_gl_window_default_get_proc_address);
+
+  G_OBJECT_CLASS (klass)->finalize = gst_gl_window_finalize;
 }
 
 GstGLWindow *
-gst_gl_window_new (void)
+gst_gl_window_new (GstGLDisplay * display)
 {
   GstGLWindow *window = NULL;
   const gchar *user_choice;
@@ -106,9 +151,43 @@ gst_gl_window_new (void)
     return NULL;
   }
 
+  window->priv->display = display;
+
   return window;
 }
 
+static void
+gst_gl_window_finalize (GObject * object)
+{
+  GstGLWindow *window = GST_GL_WINDOW (object);
+
+  if (window) {
+    gst_gl_window_set_resize_callback (window, NULL, NULL);
+    gst_gl_window_set_draw_callback (window, NULL, NULL);
+    gst_gl_window_set_close_callback (window, NULL, NULL);
+
+    if (window->priv->alive) {
+      GST_INFO ("send quit gl window loop");
+      gst_gl_window_quit (window, NULL, NULL);
+    }
+  }
+
+  if (window->priv->gl_thread) {
+    gpointer ret = g_thread_join (window->priv->gl_thread);
+    GST_INFO ("gl thread joined");
+    if (ret != NULL)
+      GST_ERROR ("gl thread returned a non-null pointer");
+    window->priv->gl_thread = NULL;
+  }
+
+  g_mutex_clear (&window->priv->render_lock);
+
+  g_cond_clear (&window->priv->cond_destroy_context);
+  g_cond_clear (&window->priv->cond_create_context);
+
+  G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object);
+}
+
 guintptr
 gst_gl_window_get_gl_context (GstGLWindow * window)
 {
@@ -209,10 +288,17 @@ gst_gl_window_quit (GstGLWindow * window, GstGLWindowCB callback, gpointer data)
 
   GST_GL_WINDOW_LOCK (window);
 
+  window->priv->alive = FALSE;
+
   window->close = callback;
   window->close_data = data;
   window_class->quit (window, callback, data);
 
+  GST_INFO ("quit sent to gl window loop");
+
+  g_cond_wait (&window->priv->cond_destroy_context, &window->priv->render_lock);
+  GST_INFO ("quit received from gl window");
+
   GST_GL_WINDOW_UNLOCK (window);
 }
 
@@ -331,7 +417,7 @@ gst_gl_window_get_proc_address (GstGLWindow * window, const gchar * name)
 
 
 gboolean
-gst_gl_window_create_context (GstGLWindow * window, GstGLAPI gl_api,
+_priv_gst_gl_window_create_context (GstGLWindow * window, GstGLAPI gl_api,
     guintptr external_gl_context, GError ** error)
 {
   gboolean ret;
@@ -368,3 +454,309 @@ gst_gl_window_default_get_proc_address (GstGLWindow * window,
 
   return ret;
 }
+
+/* Create an opengl context (one context for one GstGLDisplay) */
+gboolean
+gst_gl_window_create_context (GstGLWindow * window,
+    guintptr external_gl_context, GError ** error)
+{
+  gboolean alive = FALSE;
+  GstGLWindowClass *window_class;
+
+  g_return_val_if_fail (GST_GL_IS_WINDOW (window), FALSE);
+  window_class = GST_GL_WINDOW_GET_CLASS (window);
+  g_return_val_if_fail (window_class->create_context != NULL, FALSE);
+
+  g_mutex_lock (&window->priv->render_lock);
+
+  if (!window->priv->context_created) {
+    window->priv->external_gl_context = external_gl_context;
+    window->priv->error = error;
+
+    window->priv->gl_thread = g_thread_new ("gstglcontext",
+        (GThreadFunc) _gst_gl_window_thread_create_context, window);
+
+    g_cond_wait (&window->priv->cond_create_context,
+        &window->priv->render_lock);
+
+    window->priv->context_created = TRUE;
+
+    GST_INFO ("gl thread created");
+  }
+
+  alive = window->priv->alive;
+
+  g_mutex_unlock (&window->priv->render_lock);
+
+  return alive;
+}
+
+gboolean
+gst_gl_window_is_running (GstGLWindow * window)
+{
+  return window->priv->alive;
+}
+
+static gboolean
+_create_context_gles2 (GstGLWindow * window, gint * gl_major, gint * gl_minor)
+{
+  GstGLDisplay *display;
+  const GstGLFuncs *gl;
+  GLenum gl_err = GL_NO_ERROR;
+  GError **error;
+
+  display = window->priv->display;
+  gl = display->gl_vtable;
+  error = window->priv->error;
+
+  GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
+  GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
+      gl->GetString (GL_SHADING_LANGUAGE_VERSION));
+  GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
+  GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
+
+  gl_err = gl->GetError ();
+  if (gl_err != GL_NO_ERROR) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
+        "glGetString error: 0x%x", gl_err);
+    return FALSE;
+  }
+#if GST_GL_HAVE_GLES2
+  if (!GL_ES_VERSION_2_0) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_OLD_LIBS,
+        "OpenGL|ES >= 2.0 is required");
+    return FALSE;
+  }
+#endif
+
+  _gst_gl_feature_check_ext_functions (display, 0, 0,
+      (const gchar *) gl->GetString (GL_EXTENSIONS));
+
+  if (gl_major)
+    *gl_major = 2;
+  if (gl_minor)
+    *gl_minor = 0;
+
+  return TRUE;
+}
+
+gboolean
+_create_context_opengl (GstGLWindow * window, gint * gl_major, gint * gl_minor)
+{
+  GstGLDisplay *display;
+  const GstGLFuncs *gl;
+  guint maj, min;
+  GLenum gl_err = GL_NO_ERROR;
+  GString *opengl_version = NULL;
+  GError **error;
+
+  display = window->priv->display;
+  gl = display->gl_vtable;
+  error = window->priv->error;
+
+  GST_INFO ("GL_VERSION: %s", gl->GetString (GL_VERSION));
+  GST_INFO ("GL_SHADING_LANGUAGE_VERSION: %s",
+      gl->GetString (GL_SHADING_LANGUAGE_VERSION));
+  GST_INFO ("GL_VENDOR: %s", gl->GetString (GL_VENDOR));
+  GST_INFO ("GL_RENDERER: %s", gl->GetString (GL_RENDERER));
+
+  gl_err = gl->GetError ();
+  if (gl_err != GL_NO_ERROR) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
+        "glGetString error: 0x%x", gl_err);
+    return FALSE;
+  }
+  opengl_version =
+      g_string_truncate (g_string_new ((gchar *) gl->GetString (GL_VERSION)),
+      3);
+
+  sscanf (opengl_version->str, "%d.%d", &maj, &min);
+
+  g_string_free (opengl_version, TRUE);
+
+  /* OpenGL > 1.2.0 */
+  if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_OLD_LIBS,
+        "OpenGL >= 1.2.0 required, found %u.%u", maj, min);
+    return FALSE;
+  }
+
+  _gst_gl_feature_check_ext_functions (display, maj, min,
+      (const gchar *) gl->GetString (GL_EXTENSIONS));
+
+  if (gl_major)
+    *gl_major = maj;
+  if (gl_minor)
+    *gl_minor = min;
+
+  return TRUE;
+}
+
+GstGLAPI
+_compiled_api (void)
+{
+  GstGLAPI ret = GST_GL_API_NONE;
+
+#if GST_GL_HAVE_OPENGL
+  ret |= GST_GL_API_OPENGL;
+#endif
+#if GST_GL_HAVE_GLES2
+  ret |= GST_GL_API_GLES2;
+#endif
+
+  return ret;
+}
+
+GstGLAPI
+_parse_gl_api (const gchar * apis_s)
+{
+  GstGLAPI ret = GST_GL_API_NONE;
+  gchar *apis = (gchar *) apis_s;
+
+  while (apis) {
+    if (apis[0] == '\0') {
+      break;
+    } else if (apis[0] == ' ' || apis[0] == ',') {
+      apis = &apis[1];
+    } else if (g_strstr_len (apis, 7, "opengl3")) {
+      ret |= GST_GL_API_OPENGL3;
+      apis = &apis[7];
+    } else if (g_strstr_len (apis, 6, "opengl")) {
+      ret |= GST_GL_API_OPENGL;
+      apis = &apis[6];
+    } else if (g_strstr_len (apis, 5, "gles1")) {
+      ret |= GST_GL_API_GLES;
+      apis = &apis[5];
+    } else if (g_strstr_len (apis, 5, "gles2")) {
+      ret |= GST_GL_API_GLES2;
+      apis = &apis[5];
+    } else if (g_strstr_len (apis, 5, "gles3")) {
+      ret |= GST_GL_API_GLES3;
+      apis = &apis[5];
+    } else {
+      break;
+    }
+  }
+
+  if (ret == GST_GL_API_NONE)
+    ret = GST_GL_API_ANY;
+
+  return ret;
+}
+
+static gpointer
+_gst_gl_window_thread_create_context (GstGLWindow * window)
+{
+  GstGLWindowClass *window_class;
+  GstGLDisplay *display;
+  GstGLFuncs *gl;
+  gint gl_major = 0;
+  gboolean ret = FALSE;
+  GstGLAPI compiled_api, user_api;
+  gchar *api_string;
+  gchar *compiled_api_s;
+  gchar *user_api_string;
+  const gchar *user_choice;
+  GError **error;
+
+  window_class = GST_GL_WINDOW_GET_CLASS (window);
+  error = window->priv->error;
+  display = window->priv->display;
+
+  g_mutex_lock (&window->priv->render_lock);
+
+  gl = display->gl_vtable;
+  compiled_api = _compiled_api ();
+
+  user_choice = g_getenv ("GST_GL_API");
+
+  user_api = _parse_gl_api (user_choice);
+  user_api_string = gst_gl_api_string (user_api);
+
+  compiled_api_s = gst_gl_api_string (compiled_api);
+
+  GST_INFO ("Attempting to create opengl context. user chosen api(s):%s, "
+      "compiled api support:%s", user_api_string, compiled_api_s);
+
+  if (!window_class->create_context (window, compiled_api & user_api,
+          window->priv->external_gl_context, error)) {
+    g_assert (error == NULL || *error != NULL);
+    g_free (compiled_api_s);
+    g_free (user_api_string);
+    goto failure;
+  }
+  GST_INFO ("window created context");
+
+  display->gl_api = gst_gl_window_get_gl_api (window);
+  g_assert (display->gl_api != GST_GL_API_NONE
+      && display->gl_api != GST_GL_API_ANY);
+
+  api_string = gst_gl_api_string (display->gl_api);
+  GST_INFO ("available GL APIs: %s", api_string);
+
+  if (((compiled_api & display->gl_api) & user_api) == GST_GL_API_NONE) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_API,
+        "failed to create context, window "
+        "could not provide correct api. user:%s, compiled:%s, window:%s",
+        user_api_string, compiled_api_s, api_string);
+    g_free (api_string);
+    g_free (compiled_api_s);
+    g_free (user_api_string);
+    goto failure;
+  }
+
+  g_free (api_string);
+  g_free (compiled_api_s);
+  g_free (user_api_string);
+
+  gl->GetError = gst_gl_window_get_proc_address (window, "glGetError");
+  gl->GetString = gst_gl_window_get_proc_address (window, "glGetString");
+
+  if (!gl->GetError || !gl->GetString) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_FAILED,
+        "could not GetProcAddress core opengl functions");
+    goto failure;
+  }
+
+  /* gl api specific code */
+  if (!ret && USING_OPENGL (display))
+    ret = _create_context_opengl (window, &gl_major, NULL);
+  if (!ret && USING_GLES2 (display))
+    ret = _create_context_gles2 (window, &gl_major, NULL);
+
+  if (!ret || !gl_major) {
+    g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_CREATE_CONTEXT,
+        "GL api specific initialization failed");
+    goto failure;
+  }
+
+  g_cond_signal (&window->priv->cond_create_context);
+
+  window->priv->alive = TRUE;
+  g_mutex_unlock (&window->priv->render_lock);
+
+  gst_gl_window_run (window);
+
+  GST_INFO ("loop exited\n");
+
+  g_mutex_lock (&window->priv->render_lock);
+
+  window->priv->alive = FALSE;
+
+//  g_object_unref (G_OBJECT (display->gl_window));
+
+//  display->gl_window = NULL;
+
+  g_cond_signal (&window->priv->cond_destroy_context);
+
+  g_mutex_unlock (&window->priv->render_lock);
+
+  return NULL;
+
+failure:
+  {
+    g_cond_signal (&window->priv->cond_create_context);
+    g_mutex_unlock (&window->priv->render_lock);
+    return NULL;
+  }
+}
index 61fb693..bb89e53 100644 (file)
 #ifndef __GST_GL_WINDOW_H__
 #define __GST_GL_WINDOW_H__
 
+typedef struct _GstGLDisplay GstGLDisplay;
+
 #include <gst/gst.h>
 
 #include "gstglapi.h"
+#include "gstgldisplay.h"
 
 G_BEGIN_DECLS
 
@@ -90,6 +93,8 @@ struct _GstGLWindow {
 
   /*< private >*/
   gpointer _reserved[GST_PADDING];
+
+  GstGLWindowPrivate *priv;
 };
 
 struct _GstGLWindowClass {
@@ -119,7 +124,7 @@ struct _GstGLWindowClass {
 GQuark gst_gl_window_error_quark (void);
 GType gst_gl_window_get_type     (void);
 
-GstGLWindow * gst_gl_window_new  (void);
+GstGLWindow * gst_gl_window_new  (GstGLDisplay *display);
 
 void     gst_gl_window_set_draw_callback    (GstGLWindow *window, GstGLWindowCB callback, gpointer data);
 void     gst_gl_window_set_resize_callback  (GstGLWindow *window, GstGLWindowResizeCB callback, gpointer data);
@@ -140,11 +145,12 @@ gpointer      gst_gl_window_get_proc_address (GstGLWindow *window, const gchar *
 GstGLPlatform gst_gl_window_get_platform     (GstGLWindow *window);
 GstGLAPI      gst_gl_window_get_gl_api       (GstGLWindow *window);
 
-gboolean gst_gl_window_create_context (GstGLWindow *window, GstGLAPI gl_api,
-                                       guintptr external_gl_context, GError ** error);
+gboolean gst_gl_window_create_context (GstGLWindow *window, guintptr external_gl_context, GError ** error);
 
 gpointer gst_gl_window_default_get_proc_address (GstGLWindow *window, const gchar *name);
 
+gboolean gst_gl_window_is_running (GstGLWindow *window);
+
 GST_DEBUG_CATEGORY_EXTERN (gst_gl_window_debug);
 
 G_END_DECLS
index 8640f19..636706a 100644 (file)
 
 #include <gstgleffects.h>
 
-#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
-#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
-#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
-#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
-#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
+#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
+#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
+#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
 
 static void
 gst_gl_effects_identity_callback (gint width, gint height, guint texture,
index 20dda3d..7fd2473 100644 (file)
 
 #include <gstgleffects.h>
 
-#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
-#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
-#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
-#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
-#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
+#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
+#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
+#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
 
 static void
 gst_gl_effects_mirror_callback (gint width, gint height, guint texture,
index d55975e..0cdadfc 100644 (file)
 
 #include <gstgleffects.h>
 
-#define USING_OPENGL(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL)
-#define USING_OPENGL3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL3)
-#define USING_GLES(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES)
-#define USING_GLES2(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES2)
-#define USING_GLES3(display) (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_GLES3)
+#define USING_OPENGL(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL)
+#define USING_OPENGL3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL3)
+#define USING_GLES(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES)
+#define USING_GLES2(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES2)
+#define USING_GLES3(display) (gst_gl_display_get_gl_api (display) & GST_GL_API_GLES3)
 
 static void
 gst_gl_effects_squeeze_callback (gint width, gint height, guint texture,
index 996e9d8..2576efe 100644 (file)
@@ -86,7 +86,7 @@ gst_gl_test_src_smpte (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
 #if GST_GL_HAVE_OPENGL
   int i;
 
-  if (gst_gl_display_get_gl_api_unlocked (v->display) & GST_GL_API_OPENGL) {
+  if (gst_gl_display_get_gl_api (v->display) & GST_GL_API_OPENGL) {
 
     glClearColor (0.0, 0.0, 0.0, 1.0);
     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -192,7 +192,7 @@ void
 gst_gl_test_src_snow (GstGLTestSrc * v, GstBuffer * buffer, int w, int h)
 {
 #if GST_GL_HAVE_OPENGL
-  if (gst_gl_display_get_gl_api_unlocked (v->display) & GST_GL_API_OPENGL) {
+  if (gst_gl_display_get_gl_api (v->display) & GST_GL_API_OPENGL) {
     glClearColor (0.0, 0.0, 0.0, 1.0);
     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -219,7 +219,7 @@ gst_gl_test_src_unicolor (GstGLTestSrc * v, GstBuffer * buffer, int w,
     int h, const struct vts_color_struct *color)
 {
 #if GST_GL_HAVE_OPENGL
-  if (gst_gl_display_get_gl_api_unlocked (v->display) & GST_GL_API_OPENGL) {
+  if (gst_gl_display_get_gl_api (v->display) & GST_GL_API_OPENGL) {
     glClearColor (color->R * (1 / 255.0f), color->G * (1 / 255.0f),
         color->B * (1 / 255.0f), 1.0f);
     glClear (GL_COLOR_BUFFER_BIT);
index 854d268..25bd26b 100644 (file)
@@ -139,7 +139,7 @@ static const gchar *bumper_f_src =
     "  gl_FragColor = vec4(irradiance * textureColor.rgb, textureColor.w);\n"
     "}\n";
 
-#define LOAD_ERROR(display, msg) { gst_gl_display_set_error (display, "unable to load %s: %s", bumper->location, msg); display->isAlive = FALSE; return; }
+#define LOAD_ERROR(display, msg) { gst_gl_display_set_error (display, "unable to load %s: %s", bumper->location, msg); return; }
 
 //png reading error handler
 static void
index 985692d..8d953b6 100644 (file)
@@ -280,7 +280,7 @@ gst_gl_effects_draw_texture (GstGLEffects * effects, GLuint tex, guint width,
   GstGLFuncs *gl = display->gl_vtable;
 
 #if GST_GL_HAVE_OPENGL
-  if (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL) {
+  if (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL) {
     gfloat verts[] = { -1.0f, -1.0f,
       1.0f, -1.0f,
       1.0f, 1.0f,
@@ -347,7 +347,7 @@ set_horizontal_swap (GstGLDisplay * display, gpointer data)
 #if GST_GL_HAVE_OPENGL
   GstGLFuncs *gl = display->gl_vtable;
 
-  if (gst_gl_display_get_gl_api_unlocked (display) & GST_GL_API_OPENGL) {
+  if (gst_gl_display_get_gl_api (display) & GST_GL_API_OPENGL) {
     const gfloat mirrormatrix[16] = {
       -1.0, 0.0, 0.0, 0.0,
       0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0
index 43f116d..8526b3a 100644 (file)
@@ -289,8 +289,7 @@ gst_gl_filter_cube_filter_texture (GstGLFilter * filter, guint in_tex,
   GLCB cb = NULL;
   GstGLAPI api;
 
-  api =
-      gst_gl_display_get_gl_api_unlocked (GST_GL_FILTER (cube_filter)->display);
+  api = gst_gl_display_get_gl_api (GST_GL_FILTER (cube_filter)->display);
 
 #if GST_GL_HAVE_OPENGL
   if (api & GST_GL_API_OPENGL)
index 9012df1..77db45d 100644 (file)
@@ -412,33 +412,38 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
+      g_atomic_int_set (&glimage_sink->to_quit, 0);
       if (!glimage_sink->display) {
-        gboolean ok = FALSE;
+        GstGLWindow *window;
+        GError *error = NULL;
 
         GST_INFO ("Creating GstGLDisplay");
         glimage_sink->display = gst_gl_display_new ();
+        window = gst_gl_window_new (glimage_sink->display);
+        gst_gl_display_set_window (glimage_sink->display, window);
 
-        /* init opengl context */
-        ok = gst_gl_display_create_context (glimage_sink->display, 0);
-        if (!ok) {
+        if (!gst_gl_window_create_context (window, 0, &error)) {
           GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
-              GST_GL_DISPLAY_ERR_MSG (glimage_sink->display), (NULL));
+              ("%s", error->message), (NULL));
 
           if (glimage_sink->display) {
             g_object_unref (glimage_sink->display);
             glimage_sink->display = NULL;
           }
+          gst_object_unref (window);
 
           return GST_STATE_CHANGE_FAILURE;
         }
 
         /* setup callbacks */
-        gst_gl_window_set_resize_callback (glimage_sink->display->gl_window,
+        gst_gl_window_set_resize_callback (window,
             GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize), glimage_sink);
-        gst_gl_window_set_draw_callback (glimage_sink->display->gl_window,
+        gst_gl_window_set_draw_callback (window,
             GST_GL_WINDOW_CB (gst_glimage_sink_on_draw), glimage_sink);
-        gst_gl_window_set_close_callback (glimage_sink->display->gl_window,
+        gst_gl_window_set_close_callback (window,
             GST_GL_WINDOW_CB (gst_glimage_sink_on_close), glimage_sink);
+
+        gst_object_unref (window);
       }
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
@@ -470,14 +475,14 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
 
       GST_VIDEO_SINK_WIDTH (glimage_sink) = 1;
       GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1;
-
-      gst_gl_window_set_resize_callback (glimage_sink->display->gl_window,
-          GST_GL_WINDOW_RESIZE_CB (NULL), NULL);
-      gst_gl_window_set_draw_callback (glimage_sink->display->gl_window,
-          GST_GL_WINDOW_CB (NULL), NULL);
-      gst_gl_window_set_close_callback (glimage_sink->display->gl_window,
-          GST_GL_WINDOW_CB (NULL), NULL);
       if (glimage_sink->display) {
+        GstGLWindow *window = gst_gl_display_get_window (glimage_sink->display);
+
+        gst_gl_window_set_resize_callback (window, NULL, NULL);
+        gst_gl_window_set_draw_callback (window, NULL, NULL);
+        gst_gl_window_set_close_callback (window, NULL, NULL);
+
+        g_object_unref (window);
         g_object_unref (glimage_sink->display);
         glimage_sink->display = NULL;
       }
@@ -641,9 +646,12 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
   }
 
   if (glimage_sink->window_id != glimage_sink->new_window_id) {
+    GstGLWindow *window = gst_gl_display_get_window (glimage_sink->display);
+
     glimage_sink->window_id = glimage_sink->new_window_id;
-    gst_gl_window_set_window_handle (glimage_sink->display->gl_window,
-        glimage_sink->window_id);
+    gst_gl_window_set_window_handle (window, glimage_sink->window_id);
+
+    gst_object_unref (window);
   }
   //the buffer is cleared when an other comes in
   if (glimage_sink->stored_buffer) {
@@ -671,6 +679,12 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
 
   gst_video_frame_unmap (&frame);
 
+  if (g_atomic_int_get (&glimage_sink->to_quit) != 0) {
+    GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
+        GST_GL_DISPLAY_ERR_MSG (glimage_sink->display), (NULL));
+    return GST_FLOW_ERROR;
+  }
+
   return GST_FLOW_OK;
 
 /* ERRORS */
@@ -715,9 +729,12 @@ gst_glimage_sink_expose (GstVideoOverlay * overlay)
   if (glimage_sink->display && glimage_sink->window_id) {
 
     if (glimage_sink->window_id != glimage_sink->new_window_id) {
+      GstGLWindow *window = gst_gl_display_get_window (glimage_sink->display);
+
       glimage_sink->window_id = glimage_sink->new_window_id;
-      gst_gl_window_set_window_handle (glimage_sink->display->gl_window,
-          glimage_sink->window_id);
+      gst_gl_window_set_window_handle (window, glimage_sink->window_id);
+
+      gst_object_unref (window);
     }
 
     gst_glimage_sink_redisplay (glimage_sink, 0, 0, 0, 0, 0,
@@ -900,15 +917,19 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink)
 
   /* check if a client draw callback is registered */
   if (gl_sink->clientDrawCallback) {
+    GstGLWindow *window = gst_gl_display_get_window (gl_sink->display);
+
     gboolean doRedisplay =
         gl_sink->clientDrawCallback (gl_sink->redisplay_texture,
         gl_sink->redisplay_texture_width,
         gl_sink->redisplay_texture_height,
         gl_sink->client_data);
 
-    if (doRedisplay && gl_sink->display->gl_window)
-      gst_gl_window_draw_unlocked (gl_sink->display->gl_window,
+    if (doRedisplay && window)
+      gst_gl_window_draw_unlocked (window,
           gl_sink->redisplay_texture_width, gl_sink->redisplay_texture_height);
+
+    gst_object_unref (window);
   }
   /* default opengl scene */
   else {
@@ -990,6 +1011,8 @@ static void
 gst_glimage_sink_on_close (GstGLImageSink * gl_sink)
 {
   gst_gl_display_set_error (gl_sink->display, "Output window was closed");
+
+  g_atomic_int_set (&gl_sink->to_quit, 1);
 }
 
 static gboolean
@@ -997,15 +1020,17 @@ gst_glimage_sink_redisplay (GstGLImageSink * gl_sink, GLuint texture,
     gint gl_width, gint gl_height, gint window_width, gint window_height,
     gboolean keep_aspect_ratio)
 {
-  gboolean isAlive;
+  GstGLWindow *window;
+  gboolean alive;
+
+  window = gst_gl_display_get_window (gl_sink->display);
 
-  gst_gl_display_lock (gl_sink->display);
-  if (gl_sink->display->isAlive) {
+  if (window && gst_gl_window_is_running (window)) {
 
 #if GST_GL_HAVE_GLES2
     if (USING_GLES2 (gl_sink->display)) {
       if (!gl_sink->redisplay_shader) {
-        gst_gl_window_send_message (display->gl_window,
+        gst_gl_window_send_message (window,
             GST_GL_WINDOW_CB (gst_glimage_sink_thread_init_redisplay), display);
       }
     }
@@ -1017,14 +1042,13 @@ gst_glimage_sink_redisplay (GstGLImageSink * gl_sink, GLuint texture,
       gl_sink->redisplay_texture_height = gl_height;
     }
     gl_sink->keep_aspect_ratio = keep_aspect_ratio;
-    if (gl_sink->display->gl_window)
-      gst_gl_window_draw (gl_sink->display->gl_window, window_width,
-          window_height);
+    if (window)
+      gst_gl_window_draw (window, window_width, window_height);
   }
-  isAlive = gl_sink->display->isAlive;
-  gst_gl_display_unlock (gl_sink->display);
+  alive = gst_gl_window_is_running (window);
+  gst_object_unref (window);
 
-  return isAlive;
+  return alive;
 }
 
 void
index 2a97bf6..f75ea93 100644 (file)
@@ -70,6 +70,7 @@ struct _GstGLImageSink
     CDCB clientDrawCallback;
     gpointer client_data;
 
+    volatile gint to_quit;
     gboolean keep_aspect_ratio;
     GValue *par;
 
index 75b71ae..f228d92 100644 (file)
@@ -632,8 +632,9 @@ init_pixbuf_texture (GstGLDisplay * display, gpointer data)
       gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     }
-  } else
-    display->isAlive = FALSE;
+  }
+  //else
+  //  display->isAlive = FALSE;
 }
 
 static gboolean
index 0c7fee0..afaa70d 100644 (file)
@@ -554,11 +554,18 @@ gst_gl_test_src_start (GstBaseSrc * basesrc)
     src->display =
         g_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value)));
   else {
+    GstGLWindow *window;
+    GError *error = NULL;
+
     GST_INFO ("Creating GstGLDisplay");
     src->display = gst_gl_display_new ();
-    if (!gst_gl_display_create_context (src->display, 0)) {
+    window = gst_gl_window_new (src->display);
+    gst_gl_display_set_window (src->display, window);
+    g_object_unref (window);
+
+    if (!gst_gl_window_create_context (window, 0, &error)) {
       GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
-          GST_GL_DISPLAY_ERR_MSG (src->display), (NULL));
+          ("%s", error->message), (NULL));
       return FALSE;
     }
   }