diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 9f47797097..e9d60b8e99 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -8,6 +8,7 @@ noinst_HEADERS = libgstgl_@GST_API_VERSION@_la_SOURCES = \ gstgldisplay.c \ + gstglcontext.c \ gstglmemory.c \ gstglbufferpool.c \ gstglfilter.c \ @@ -64,6 +65,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gstglconfig.h \ gstglwindow.h \ gstgldisplay.h \ + gstglcontext.h \ gstglmemory.h \ gstglbufferpool.h \ gstgles2.h \ diff --git a/gst-libs/gst/gl/android/gstglwindow_android_egl.c b/gst-libs/gst/gl/android/gstglwindow_android_egl.c index 1726068018..78ab730b60 100644 --- a/gst-libs/gst/gl/android/gstglwindow_android_egl.c +++ b/gst-libs/gst/gl/android/gstglwindow_android_egl.c @@ -28,6 +28,9 @@ #include "config.h" #endif +#include "../gstgl_fwd.h" +#include + #include "gstglwindow_android_egl.h" #define GST_CAT_DEFAULT gst_gl_window_debug @@ -307,13 +310,14 @@ static gpointer gst_gl_window_android_egl_get_proc_address (GstGLWindow * window, const gchar * name) { + GstGLContext *context = NULL; GstGLWindowAndroidEGL *window_egl; gpointer result; window_egl = GST_GL_WINDOW_ANDROID_EGL (window); if (!(result = gst_gl_egl_get_proc_address (window_egl->egl, name))) { - result = gst_gl_window_default_get_proc_address (window, name); + result = gst_gl_context_default_get_proc_address (context, name); } return result; diff --git a/gst-libs/gst/gl/gl.h b/gst-libs/gst/gl/gl.h index 3f3a2774a6..07d9478120 100644 --- a/gst-libs/gst/gl/gl.h +++ b/gst-libs/gst/gl/gl.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/gst-libs/gst/gl/gstgl_fwd.h b/gst-libs/gst/gl/gstgl_fwd.h index b1305042fb..8de50c2324 100644 --- a/gst-libs/gst/gl/gstgl_fwd.h +++ b/gst-libs/gst/gl/gstgl_fwd.h @@ -31,6 +31,10 @@ typedef struct _GstGLDisplay GstGLDisplay; typedef struct _GstGLDisplayClass GstGLDisplayClass; typedef struct _GstGLDisplayPrivate GstGLDisplayPrivate; +typedef struct _GstGLContext GstGLContext; +typedef struct _GstGLContextClass GstGLContextClass; +typedef struct _GstGLContextPrivate GstGLContextPrivate; + typedef struct _GstGLWindow GstGLWindow; typedef struct _GstGLWindowPrivate GstGLWindowPrivate; typedef struct _GstGLWindowClass GstGLWindowClass; diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c new file mode 100644 index 0000000000..7bd8754bcb --- /dev/null +++ b/gst-libs/gst/gl/gstglcontext.c @@ -0,0 +1,624 @@ +/* + * GStreamer + * Copyright (C) 2013 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "gl.h" +#include "gstglcontext.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_context_debug +GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); + +#define gst_gl_context_parent_class parent_class +G_DEFINE_TYPE (GstGLContext, gst_gl_context, G_TYPE_OBJECT); + +#define GST_GL_CONTEXT_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT, GstGLContextPrivate)) + +static gpointer gst_gl_context_create_thread (GstGLContext * context); +static void gst_gl_context_finalize (GObject * object); + +struct _GstGLContextPrivate +{ + GstGLDisplay *display; + + GThread *gl_thread; + + /* conditions */ + GMutex render_lock; + GCond create_cond; + GCond destroy_cond; + + gboolean created; + gboolean alive; + + guintptr external_gl_context; + GstGLAPI gl_api; + GError **error; +}; + +GQuark +gst_gl_context_error_quark (void) +{ + return g_quark_from_static_string ("gst-gl-context-error-quark"); +} + +static void +_ensure_window (GstGLContext * context) +{ + GstGLWindow *window; + + if (context->window) + return; + + window = gst_gl_window_new (context->priv->display); + + gst_gl_context_set_window (context, window); +} + +static void +gst_gl_context_init (GstGLContext * context) +{ + context->priv = GST_GL_CONTEXT_GET_PRIVATE (context); + + g_mutex_init (&context->priv->render_lock); + + g_cond_init (&context->priv->create_cond); + g_cond_init (&context->priv->destroy_cond); + context->priv->created = FALSE; +} + +static void +gst_gl_context_class_init (GstGLContextClass * klass) +{ + g_type_class_add_private (klass, sizeof (GstGLContextPrivate)); + + klass->get_proc_address = + GST_DEBUG_FUNCPTR (gst_gl_context_default_get_proc_address); + + G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize; +} + +GstGLContext * +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); + } + + user_choice = g_getenv ("GST_GL_PLATFORM"); + GST_INFO ("creating a context, user choice:%s", user_choice); +#if 0 +#if GST_GL_HAVE_PLATFORM_EGL + if (!context && (!user_choice || g_strstr_len (user_choice, 7, "egl"))) + context = GST_GL_CONTEXT (gst_gl_context_egl_new ()); +#endif +#if GST_GL_HAVE_PLATFORM_GLX + if (!context && (!user_choice || g_strstr_len (user_choice, 3, "glx"))) + context = GST_GL_CONTEXT (gst_gl_context_glx_new ()); +#endif +#if GST_GL_HAVE_PLATFORM_WIN32 + if (!context && (!user_choice || g_strstr_len (user_choice, 5, "win32"))) + context = GST_GL_CONTEXT (gst_gl_context_win32_new ()); +#endif +#if GST_GL_HAVE_PLATFORM_COCOA + if (!context && (!user_choice || g_strstr_len (user_choice, 5, "cocoa"))) { + context = GST_GL_CONTEXT (gst_gl_context_cocoa_new ()); + } +#endif + if (!context) { + /* subclass returned a NULL context */ + GST_WARNING ("Could not create context. user specified %s", + user_choice ? user_choice : "(null)"); + + return NULL; + } +#endif + + context = g_object_new (GST_GL_TYPE_CONTEXT, NULL); + + context->priv->display = display; + + 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) { + GST_INFO ("send quit gl window loop"); + gst_gl_window_quit (context->window); + g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock); + } + + 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; + } + + gst_object_unref (context->window); + + g_mutex_clear (&context->priv->render_lock); + + g_cond_clear (&context->priv->destroy_cond); + g_cond_clear (&context->priv->create_cond); + + G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object); +} + +/* FIXME move the relevant window vfuncs into GstGLContext */ +gboolean +gst_gl_context_activate (GstGLContext * context, gboolean activate) +{ + GstGLWindowClass *window_class; + gboolean result; + + g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE); + window_class = GST_GL_WINDOW_GET_CLASS (context->window); + g_return_val_if_fail (window_class->activate != NULL, FALSE); + + result = window_class->activate (context->window, activate); + + return result; +} + +GstGLAPI +gst_gl_context_get_gl_api (GstGLContext * context) +{ + GstGLWindowClass *window_class; + + g_return_val_if_fail (GST_GL_IS_CONTEXT (context), GST_GL_API_NONE); + window_class = GST_GL_WINDOW_GET_CLASS (context->window); + g_return_val_if_fail (window_class->get_gl_api != NULL, GST_GL_API_NONE); + + return window_class->get_gl_api (context->window); +} + +gpointer +gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name) +{ + gpointer ret; + GstGLWindowClass *window_class; + + g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL); + window_class = GST_GL_WINDOW_GET_CLASS (context->window); + g_return_val_if_fail (window_class->get_proc_address != NULL, NULL); + + ret = window_class->get_proc_address (context->window, name); + + return ret; +} + +gpointer +gst_gl_context_default_get_proc_address (GstGLContext * context, + const gchar * name) +{ + static GModule *module = NULL; + gpointer ret = NULL; + + if (!module) + module = g_module_open (NULL, G_MODULE_BIND_LAZY); + + if (module) { + if (!g_module_symbol (module, name, &ret)) + return NULL; + } + + return ret; +} + +gboolean +gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window) +{ + /* we can't change the window while we are running */ + if (context->priv->alive) + return FALSE; + + if (window) { + if (gst_gl_window_is_running (window)) + return FALSE; + + g_weak_ref_set (&window->context_ref, context); + } + + if (context->window) + gst_object_unref (context->window); + + context->window = window ? gst_object_ref (window) : NULL; + + return TRUE; +} + +GstGLWindow * +gst_gl_context_get_window (GstGLContext * context) +{ + g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL); + + _ensure_window (context); + + return gst_object_ref (context->window); +} + +/* Create an opengl context (one context for one GstGLDisplay) */ +gboolean +gst_gl_context_create (GstGLContext * context, + guintptr external_gl_context, GError ** error) +{ + gboolean alive = FALSE; + GstGLWindowClass *window_class; + + g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE); + window_class = GST_GL_WINDOW_GET_CLASS (context->window); + g_return_val_if_fail (window_class->create_context != NULL, FALSE); + + _ensure_window (context); + + g_mutex_lock (&context->priv->render_lock); + + if (window_class->open) { + if (!(alive = window_class->open (context->window, error))) + goto out; + } + + if (!context->priv->created) { + context->priv->external_gl_context = external_gl_context; + context->priv->error = error; + + context->priv->gl_thread = g_thread_new ("gstglcontext", + (GThreadFunc) gst_gl_context_create_thread, context); + + g_cond_wait (&context->priv->create_cond, &context->priv->render_lock); + + context->priv->created = TRUE; + + GST_INFO ("gl thread created"); + } + + alive = context->priv->alive; + + g_mutex_unlock (&context->priv->render_lock); + +out: + return alive; +} + +static gboolean +_create_context_gles2 (GstGLContext * context, gint * gl_major, gint * gl_minor, + GError ** error) +{ + GstGLDisplay *display; + const GstGLFuncs *gl; + GLenum gl_err = GL_NO_ERROR; + + display = context->priv->display; + 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) { + g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_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_CONTEXT_ERROR, GST_GL_CONTEXT_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 (GstGLContext * context, gint * gl_major, + gint * gl_minor, GError ** error) +{ + GstGLDisplay *display; + const GstGLFuncs *gl; + guint maj, min; + GLenum gl_err = GL_NO_ERROR; + GString *opengl_version = NULL; + + display = context->priv->display; + 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) { + g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_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_CONTEXT_ERROR, GST_GL_CONTEXT_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 | GST_GL_API_OPENGL3; +#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; +} + +//gboolean +//gst_gl_context_create (GstGLContext * context, guintptr external_gl_context, GError ** error) +static gpointer +gst_gl_context_create_thread (GstGLContext * context) +{ + 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; + guintptr external_gl_context; + + error = context->priv->error; + external_gl_context = context->priv->external_gl_context; + + window_class = GST_GL_WINDOW_GET_CLASS (context->window); + + if (window_class->open) { + if (!window_class->open (context->window, error)) + goto failure; + } + + display = context->priv->display; + 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); + + if ((user_api & compiled_api) == GST_GL_API_NONE) { + g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, + "Cannot create context with the user requested api (%s). " + "We have support for (%s)", user_api_string, compiled_api_s); + g_free (user_api_string); + g_free (compiled_api_s); + goto failure; + } + + 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 (context->window, compiled_api & user_api, + external_gl_context, error)) { + g_assert (error == NULL || *error != NULL); + g_free (compiled_api_s); + g_free (user_api_string); + goto failure; + } + GST_INFO ("context created context"); + + display->gl_api = gst_gl_context_get_gl_api (context); + 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_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, + "failed to create context, context " + "could not provide correct api. user (%s), compiled (%s), context (%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_context_get_proc_address (context, "glGetError"); + gl->GetString = gst_gl_context_get_proc_address (context, "glGetString"); + + if (!gl->GetError || !gl->GetString) { + g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, + "could not GetProcAddress core opengl functions"); + goto failure; + } + + /* gl api specific code */ + if (!ret && USING_OPENGL (display)) + ret = _create_context_opengl (context, &gl_major, NULL, error); + if (!ret && USING_GLES2 (display)) + ret = _create_context_gles2 (context, &gl_major, NULL, error); + + if (!ret) + goto failure; + + context->priv->alive = TRUE; + + g_cond_signal (&context->priv->create_cond); + g_mutex_unlock (&context->priv->render_lock); + + gst_gl_window_run (context->window); + + GST_INFO ("loop exited\n"); + + g_mutex_lock (&context->priv->render_lock); + + context->priv->alive = FALSE; + + if (window_class->close) { + window_class->close (context->window); + } + + context_class->activate (context, FALSE); + + context_class->destroy_context (context); + + if (context->window->close) + context->window->close (context->window->close_data); + + g_cond_signal (&context->priv->destroy_cond); + + g_mutex_unlock (&context->priv->render_lock); + + return NULL; + +failure: + { + g_cond_signal (&context->priv->create_cond); + g_mutex_unlock (&context->priv->render_lock); + return NULL; + } +} + +guintptr +gst_gl_context_get_gl_context (GstGLContext * context) +{ + GstGLContextClass *context_class; + guintptr result; + + 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_context != NULL, 0); + + result = context_class->get_gl_context (context); + + return result; +} diff --git a/gst-libs/gst/gl/gstglcontext.h b/gst-libs/gst/gl/gstglcontext.h new file mode 100644 index 0000000000..10c30a7011 --- /dev/null +++ b/gst-libs/gst/gl/gstglcontext.h @@ -0,0 +1,98 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_GL_CONTEXT_H__ +#define __GST_GL_CONTEXT_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_CONTEXT (gst_gl_context_get_type()) +#define GST_GL_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_CONTEXT, GstGLContext)) +#define GST_GL_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_CONTEXT, GstGLContextClass)) +#define GST_GL_IS_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_CONTEXT)) +#define GST_GL_IS_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_CONTEXT)) +#define GST_GL_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_CONTEXT, GstGLContextClass)) +GType gst_gl_context_get_type (void); + +#define GST_GL_CONTEXT_ERROR (gst_gl_context_error_quark ()) +GQuark gst_gl_window_error_quark (void); + +typedef enum +{ + GST_GL_CONTEXT_ERROR_FAILED, + GST_GL_CONTEXT_ERROR_WRONG_CONFIG, + GST_GL_CONTEXT_ERROR_WRONG_API, + GST_GL_CONTEXT_ERROR_OLD_LIBS, + GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, + GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, +} GstGLContextError; + +struct _GstGLContext { + /*< private >*/ + GObject parent; + + /*< public >*/ + GstGLWindow *window; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; + + GstGLContextPrivate *priv; +}; + +struct _GstGLContextClass { + /*< private >*/ + 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 (*create_context) (GstGLContext *context, GstGLAPI gl_api, + guintptr external_gl_context, GError ** error); + + /*< private >*/ + gpointer _reserved[GST_PADDING]; +}; + +/* methods */ + +GstGLContext * gst_gl_context_new (GstGLDisplay *display); + +gboolean gst_gl_context_activate (GstGLContext *context, gboolean activate); + +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); + +gboolean gst_gl_context_create (GstGLContext *context, guintptr external_gl_context, GError ** error); + +gpointer gst_gl_context_default_get_proc_address (GstGLContext *context, const gchar *name); + +gboolean gst_gl_context_set_window (GstGLContext *context, GstGLWindow *window); +GstGLWindow * gst_gl_context_get_window (GstGLContext *context); + +G_END_DECLS + +#endif /* __GST_GL_CONTEXT_H__ */ diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 2dd1540ba9..ed0e886f16 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -81,14 +81,21 @@ gst_gl_display_finalize (GObject * object) display->gl_vtable = NULL; } - if (display->window) { - gst_object_unref (display->window); - display->window = NULL; + if (display->context) { + gst_object_unref (display->context); + display->context = NULL; } G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object); } +GstGLDisplay * +gst_gl_display_new (void) +{ + return g_object_new (GST_TYPE_GL_DISPLAY, NULL); +} + +#if 1 typedef struct { GstGLDisplay *display; @@ -104,37 +111,36 @@ _gst_gl_display_thread_run_generic (RunGenericData * data) data->func (data->display, data->data); } -GstGLDisplay * -gst_gl_display_new (void) -{ - return g_object_new (GST_TYPE_GL_DISPLAY, NULL); -} - void gst_gl_display_thread_add (GstGLDisplay * display, GstGLDisplayThreadFunc func, gpointer data) { + GstGLWindow *window; RunGenericData rdata; g_return_if_fail (GST_IS_GL_DISPLAY (display)); - g_return_if_fail (GST_GL_IS_WINDOW (display->window)); + g_return_if_fail (GST_GL_IS_CONTEXT (display->context)); g_return_if_fail (func != NULL); rdata.display = display; rdata.data = data; rdata.func = func; - gst_gl_window_send_message (display->window, + window = gst_gl_context_get_window (display->context); + + gst_gl_window_send_message (window, GST_GL_WINDOW_CB (_gst_gl_display_thread_run_generic), &rdata); + + gst_object_unref (window); } GstGLAPI gst_gl_display_get_gl_api (GstGLDisplay * display) { g_return_val_if_fail (GST_IS_GL_DISPLAY (display), GST_GL_API_NONE); - g_return_val_if_fail (GST_GL_IS_WINDOW (display->window), GST_GL_API_NONE); + g_return_val_if_fail (GST_GL_IS_CONTEXT (display->context), GST_GL_API_NONE); - return gst_gl_window_get_gl_api (display->window); + return gst_gl_context_get_gl_api (display->context); } gpointer @@ -144,45 +150,46 @@ gst_gl_display_get_gl_vtable (GstGLDisplay * display) return display->gl_vtable; } +#endif void -gst_gl_display_set_window (GstGLDisplay * display, GstGLWindow * window) +gst_gl_display_set_context (GstGLDisplay * display, GstGLContext * context) { g_return_if_fail (GST_IS_GL_DISPLAY (display)); - g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_return_if_fail (GST_GL_IS_CONTEXT (context)); gst_gl_display_lock (display); - if (display->window) - gst_object_unref (display->window); + if (display->context) + gst_object_unref (display->context); - display->window = gst_object_ref (window); + display->context = gst_object_ref (context); gst_gl_display_unlock (display); } -GstGLWindow * -gst_gl_display_get_window (GstGLDisplay * display) +GstGLContext * +gst_gl_display_get_context (GstGLDisplay * display) { - GstGLWindow *window; + GstGLContext *context; g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL); gst_gl_display_lock (display); - window = display->window ? gst_object_ref (display->window) : NULL; + context = display->context ? gst_object_ref (display->context) : NULL; gst_gl_display_unlock (display); - return window; + return context; } -GstGLWindow * -gst_gl_display_get_window_unlocked (GstGLDisplay * display) +GstGLContext * +gst_gl_display_get_context_unlocked (GstGLDisplay * display) { g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL); - return display->window ? gst_object_ref (display->window) : NULL; + return display->context ? gst_object_ref (display->context) : NULL; } void diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index 9cbb21a687..a430a32e05 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -57,7 +57,7 @@ struct _GstGLDisplay GstObject object; /* */ - GstGLWindow *window; + GstGLContext *context; GstGLAPI gl_api; GstGLFuncs *gl_vtable; @@ -75,11 +75,11 @@ GstGLDisplay *gst_gl_display_new (void); #define gst_gl_display_lock(display) GST_OBJECT_LOCK (display) #define gst_gl_display_unlock(display) GST_OBJECT_UNLOCK (display) -GstGLAPI gst_gl_display_get_gl_api (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); +GstGLAPI gst_gl_display_get_gl_api (GstGLDisplay * display); +gpointer gst_gl_display_get_gl_vtable (GstGLDisplay * display); +void gst_gl_display_set_context (GstGLDisplay * display, GstGLContext * context); +GstGLContext * gst_gl_display_get_context (GstGLDisplay * display); +GstGLContext * gst_gl_display_get_context_unlocked (GstGLDisplay * display); void gst_gl_display_thread_add (GstGLDisplay * display, GstGLDisplayThreadFunc func, gpointer data); diff --git a/gst-libs/gst/gl/gstglfeature.c b/gst-libs/gst/gl/gstglfeature.c index f599e484b7..df6f0fdb5c 100644 --- a/gst-libs/gst/gl/gstglfeature.c +++ b/gst-libs/gst/gl/gstglfeature.c @@ -149,7 +149,7 @@ _gst_gl_feature_check (GstGLDisplay * display, const char *suffix = NULL; int func_num; GstGLFuncs *gst_gl = display->gl_vtable; - GstGLWindow *window = NULL; + GstGLContext *context = NULL; /* First check whether the functions should be directly provided by GL */ @@ -172,8 +172,8 @@ _gst_gl_feature_check (GstGLDisplay * display, if (suffix == NULL) goto error; - window = gst_gl_display_get_window (display); - g_assert (window); + context = gst_gl_display_get_context (display); + g_assert (context); /* Try to get all of the entry points */ for (func_num = 0; data->functions[func_num].name; func_num++) { @@ -186,7 +186,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 (window, full_function_name); + func = gst_gl_context_get_proc_address (context, full_function_name); if (func == NULL && in_core) { GST_TRACE ("%s was not found in core, trying the extension version", @@ -198,7 +198,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 (window, full_function_name); + func = gst_gl_context_get_proc_address (context, full_function_name); } } @@ -213,7 +213,7 @@ _gst_gl_feature_check (GstGLDisplay * display, } g_free (full_function_name); - gst_object_unref (window); + gst_object_unref (context); return TRUE; @@ -232,8 +232,8 @@ error: g_free (full_function_name); } - if (window) - gst_object_unref (window); + if (context) + gst_object_unref (context); return FALSE; } diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c index b6743dca93..d93903fd1f 100644 --- a/gst-libs/gst/gl/gstglfilter.c +++ b/gst-libs/gst/gl/gstglfilter.c @@ -256,16 +256,16 @@ gst_gl_filter_start (GstBaseTransform * bt) filter->display = gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); else { - GstGLWindow *window; + GstGLContext *context; GError *error = NULL; GST_INFO ("Creating GstGLDisplay"); filter->display = gst_gl_display_new (); - window = gst_gl_window_new (filter->display); - gst_gl_display_set_window (filter->display, window); - gst_object_unref (window); + context = gst_gl_context_new (filter->display); + gst_gl_display_set_context (filter->display, context); + gst_object_unref (context); - if (!gst_gl_window_create_context (window, 0, &error)) { + if (!gst_gl_context_create (context, 0, &error)) { GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE; diff --git a/gst-libs/gst/gl/gstglmixer.c b/gst-libs/gst/gl/gstglmixer.c index 748e5a8b63..53a3c2ccd0 100644 --- a/gst-libs/gst/gl/gstglmixer.c +++ b/gst-libs/gst/gl/gstglmixer.c @@ -935,16 +935,16 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate) mix->display = gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); else { - GstGLWindow *window; + GstGLContext *context; GError *error = NULL; GST_INFO ("Creating GstGLDisplay"); mix->display = gst_gl_display_new (); - window = gst_gl_window_new (mix->display); - gst_gl_display_set_window (mix->display, window); - gst_object_unref (window); + context = gst_gl_context_new (mix->display); + gst_gl_display_set_context (mix->display, context); + gst_object_unref (context); - if (!gst_gl_window_create_context (window, 0, &error)) { + if (!gst_gl_context_create (context, 0, &error)) { GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE; diff --git a/gst-libs/gst/gl/gstglutils.c b/gst-libs/gst/gl/gstglutils.c index 02bfb7deb6..403968292a 100644 --- a/gst-libs/gst/gl/gstglutils.c +++ b/gst-libs/gst/gl/gstglutils.c @@ -141,32 +141,34 @@ gst_gl_display_check_framebuffer_status (GstGLDisplay * display) void gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activate) { - GstGLWindow *window; + GstGLContext *context; g_return_if_fail (GST_IS_GL_DISPLAY (display)); if (!activate) gst_gl_display_lock (display); - window = gst_gl_display_get_window_unlocked (display); + context = gst_gl_display_get_context_unlocked (display); - gst_gl_window_activate (window, activate); + gst_gl_context_activate (context, activate); if (activate) gst_gl_display_unlock (display); - gst_object_unref (window); + gst_object_unref (context); } void gst_gl_display_gen_texture (GstGLDisplay * display, GLuint * pTexture, GstVideoFormat v_format, GLint width, GLint height) { + GstGLContext *context; GstGLWindow *window; gst_gl_display_lock (display); - window = gst_gl_display_get_window_unlocked (display); + context = gst_gl_display_get_context_unlocked (display); + window = gst_gl_context_get_window (context); if (gst_gl_window_is_running (window)) { gen_texture_width = width; @@ -178,6 +180,7 @@ gst_gl_display_gen_texture (GstGLDisplay * display, GLuint * pTexture, } else *pTexture = 0; + gst_object_unref (context); gst_object_unref (window); gst_gl_display_unlock (display); @@ -186,17 +189,20 @@ gst_gl_display_gen_texture (GstGLDisplay * display, GLuint * pTexture, void gst_gl_display_del_texture (GstGLDisplay * display, GLuint * pTexture) { + GstGLContext *context; GstGLWindow *window; gst_gl_display_lock (display); - window = gst_gl_display_get_window_unlocked (display); + context = gst_gl_display_get_context_unlocked (display); + window = gst_gl_context_get_window (context); if (gst_gl_window_is_running (window) && *pTexture) { del_texture = pTexture; gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_gl_display_del_texture_window_cb), display); } + gst_object_unref (context); gst_object_unref (window); gst_gl_display_unlock (display); diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c index fe28edb150..8349c434e4 100644 --- a/gst-libs/gst/gl/gstglwindow.c +++ b/gst-libs/gst/gl/gstglwindow.c @@ -78,7 +78,6 @@ struct _GstGLWindowPrivate GError **error; }; -static gpointer _gst_gl_window_thread_create_context (GstGLWindow * window); static void gst_gl_window_finalize (GObject * object); GQuark @@ -99,6 +98,8 @@ gst_gl_window_init (GstGLWindow * window) g_cond_init (&window->priv->cond_create_context); g_cond_init (&window->priv->cond_destroy_context); window->priv->context_created = FALSE; + + g_weak_ref_init (&window->context_ref, NULL); } static void @@ -106,9 +107,6 @@ 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; } @@ -167,28 +165,7 @@ gst_gl_window_finalize (GObject * object) { GstGLWindow *window = GST_GL_WINDOW (object); - gst_gl_window_set_resize_callback (window, NULL, NULL, NULL); - gst_gl_window_set_draw_callback (window, NULL, NULL, NULL); - - if (window->priv->alive) { - GST_INFO ("send quit gl window loop"); - gst_gl_window_quit (window); - } - - gst_gl_window_set_close_callback (window, NULL, 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_weak_ref_clear (&window->context_ref); G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object); } @@ -278,6 +255,7 @@ gst_gl_window_run (GstGLWindow * window) g_return_if_fail (window_class->run != NULL); GST_GL_WINDOW_LOCK (window); + window->priv->alive = TRUE; window_class->run (window); GST_GL_WINDOW_UNLOCK (window); } @@ -301,7 +279,6 @@ gst_gl_window_quit (GstGLWindow * window) GST_GL_WINDOW_UNLOCK (window); - g_cond_wait (&window->priv->cond_destroy_context, &window->priv->render_lock); GST_INFO ("quit received from gl window"); } @@ -423,338 +400,16 @@ gst_gl_window_get_proc_address (GstGLWindow * window, const gchar * name) return ret; } -gpointer -gst_gl_window_default_get_proc_address (GstGLWindow * window, - const gchar * name) -{ - static GModule *module = NULL; - gpointer ret = NULL; - - if (!module) - module = g_module_open (NULL, G_MODULE_BIND_LAZY); - - if (module) { - if (!g_module_symbol (module, name, &ret)) - return NULL; - } - - 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_class->open) { - if (!(alive = window_class->open (window, error))) - goto out; - } - - 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); - -out: - 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, - GError ** error) +GstGLContext * +gst_gl_window_get_context (GstGLWindow * window) { - GstGLDisplay *display; - const GstGLFuncs *gl; - GLenum gl_err = GL_NO_ERROR; + g_return_val_if_fail (GST_GL_IS_WINDOW (window), NULL); - display = window->priv->display; - 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) { - 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, - GError ** error) -{ - GstGLDisplay *display; - const GstGLFuncs *gl; - guint maj, min; - GLenum gl_err = GL_NO_ERROR; - GString *opengl_version = NULL; - - display = window->priv->display; - 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) { - 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 | GST_GL_API_OPENGL3; -#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); - - if ((user_api & compiled_api) == GST_GL_API_NONE) { - g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_API, - "Cannot create context with the user requested api (%s). " - "We have support for (%s)", user_api_string, compiled_api_s); - g_free (user_api_string); - g_free (compiled_api_s); - goto failure; - } - - 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, error); - if (!ret && USING_GLES2 (display)) - ret = _create_context_gles2 (window, &gl_major, NULL, error); - - if (!ret) - 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; - - if (window_class->close) { - window_class->close (window); - if (window->close) - window->close (window->close_data); - } - - 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; - } + return (GstGLContext *) g_weak_ref_get (&window->context_ref); } diff --git a/gst-libs/gst/gl/gstglwindow.h b/gst-libs/gst/gl/gstglwindow.h index e19e75c4a6..f7aae8c5c6 100644 --- a/gst-libs/gst/gl/gstglwindow.h +++ b/gst-libs/gst/gl/gstglwindow.h @@ -75,6 +75,8 @@ struct _GstGLWindow { GMutex lock; gboolean need_lock; + GWeakRef context_ref; + guintptr external_gl_context; GstGLWindowCB draw; @@ -131,7 +133,6 @@ void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB void gst_gl_window_set_need_lock (GstGLWindow *window, gboolean need_lock); guintptr gst_gl_window_get_gl_context (GstGLWindow *window); -gboolean gst_gl_window_activate (GstGLWindow *window, gboolean activate); void gst_gl_window_set_window_handle (GstGLWindow *window, guintptr handle); guintptr gst_gl_window_get_window_handle (GstGLWindow *window); void gst_gl_window_draw_unlocked (GstGLWindow *window, guint width, guint height); @@ -140,13 +141,7 @@ void gst_gl_window_run (GstGLWindow *window); void gst_gl_window_quit (GstGLWindow *window); void gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data); -gpointer gst_gl_window_get_proc_address (GstGLWindow *window, const gchar *name); -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, guintptr external_gl_context, GError ** error); - -gpointer gst_gl_window_default_get_proc_address (GstGLWindow *window, const gchar *name); +GstGLContext * gst_gl_window_get_context (GstGLWindow *window); gboolean gst_gl_window_is_running (GstGLWindow *window); diff --git a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c index f8c06ada8e..16215d5137 100644 --- a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +++ b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c @@ -27,6 +27,9 @@ #include "wayland_event_source.h" +#include "../gstgl_fwd.h" +#include + #include "gstglwindow_wayland_egl.h" const gchar *WlEGLErrorString (); @@ -572,13 +575,14 @@ static gpointer gst_gl_window_wayland_egl_get_proc_address (GstGLWindow * window, const gchar * name) { + GstGLContext *context = NULL; GstGLWindowWaylandEGL *window_egl; gpointer result; window_egl = GST_GL_WINDOW_WAYLAND_EGL (window); if (!(result = gst_gl_egl_get_proc_address (window_egl->egl, name))) { - result = gst_gl_window_default_get_proc_address (window, name); + result = gst_gl_context_default_get_proc_address (context, name); } return result; diff --git a/gst-libs/gst/gl/win32/gstglwindow_win32_egl.c b/gst-libs/gst/gl/win32/gstglwindow_win32_egl.c index 6229c51817..6aa4903e4b 100644 --- a/gst-libs/gst/gl/win32/gstglwindow_win32_egl.c +++ b/gst-libs/gst/gl/win32/gstglwindow_win32_egl.c @@ -25,6 +25,9 @@ #include +#include "../gstgl_fwd.h" +#include + #include "gstglwindow_win32_egl.h" static guintptr gst_gl_window_win32_wgl_get_gl_context (GstGLWindowWin32 * diff --git a/gst-libs/gst/gl/win32/gstglwindow_win32_wgl.c b/gst-libs/gst/gl/win32/gstglwindow_win32_wgl.c index e85a01131d..063596710e 100644 --- a/gst-libs/gst/gl/win32/gstglwindow_win32_wgl.c +++ b/gst-libs/gst/gl/win32/gstglwindow_win32_wgl.c @@ -27,6 +27,9 @@ #include +#include "../gstgl_fwd.h" +#include + #include "gstglwindow_win32_wgl.h" #define GST_CAT_DEFAULT gst_gl_window_debug @@ -215,10 +218,11 @@ static gpointer gst_gl_window_win32_wgl_get_proc_address (GstGLWindow * window, const gchar * name) { + GstGLContext *context; gpointer result; if (!(result = wglGetProcAddress ((LPCSTR) name))) { - result = gst_gl_window_default_get_proc_address (window, name); + result = gst_gl_context_default_get_proc_address (context, name); } return result; diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11_egl.c b/gst-libs/gst/gl/x11/gstglwindow_x11_egl.c index 7ff13478c0..45413fba8a 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11_egl.c +++ b/gst-libs/gst/gl/x11/gstglwindow_x11_egl.c @@ -25,6 +25,9 @@ #include "config.h" #endif +#include "../gstgl_fwd.h" +#include + #include "gstglwindow_x11_egl.h" const gchar *X11EGLErrorString (); @@ -188,11 +191,12 @@ static gpointer gst_gl_window_x11_egl_get_proc_address (GstGLWindow * window, const gchar * name) { + GstGLContext *context = NULL; GstGLWindowX11EGL *window_egl = GST_GL_WINDOW_X11_EGL (window); gpointer result; if (!(result = gst_gl_egl_get_proc_address (window_egl->egl, name))) { - result = gst_gl_window_default_get_proc_address (window, name); + result = gst_gl_context_default_get_proc_address (context, name); } return result; diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11_glx.c b/gst-libs/gst/gl/x11/gstglwindow_x11_glx.c index d62a990c46..932502945d 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11_glx.c +++ b/gst-libs/gst/gl/x11/gstglwindow_x11_glx.c @@ -27,6 +27,9 @@ #include +#include "../gstgl_fwd.h" +#include + #include #include "gstglwindow_x11_glx.h" @@ -352,10 +355,11 @@ static gpointer gst_gl_window_x11_glx_get_proc_address (GstGLWindow * window, const gchar * name) { + GstGLContext *context = NULL; gpointer result; if (!(result = glXGetProcAddressARB ((const GLubyte *) name))) { - result = gst_gl_window_default_get_proc_address (window, name); + result = gst_gl_context_default_get_proc_address (context, name); } return result; diff --git a/gst/gl/gstglimagesink.c b/gst/gl/gstglimagesink.c index 5aede4329b..9741622dca 100644 --- a/gst/gl/gstglimagesink.c +++ b/gst/gl/gstglimagesink.c @@ -415,12 +415,14 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) g_atomic_int_set (&glimage_sink->to_quit, 0); if (!glimage_sink->display) { GstGLWindow *window; + GstGLContext *context; 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); + context = gst_gl_context_new (glimage_sink->display); + gst_gl_display_set_context (glimage_sink->display, context); + window = gst_gl_context_get_window (context); if (!glimage_sink->window_id && !glimage_sink->new_window_id) gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY @@ -431,7 +433,7 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) gst_gl_window_set_window_handle (window, glimage_sink->window_id); } - if (!gst_gl_window_create_context (window, 0, &error)) { + if (!gst_gl_context_create (context, 0, &error)) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); @@ -439,7 +441,7 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } - gst_object_unref (window); + gst_object_unref (context); return GST_STATE_CHANGE_FAILURE; } @@ -456,6 +458,7 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_object_unref (window); + gst_object_unref (context); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: @@ -494,7 +497,9 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) GST_VIDEO_SINK_WIDTH (glimage_sink) = 1; GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1; if (glimage_sink->display) { - GstGLWindow *window = gst_gl_display_get_window (glimage_sink->display); + GstGLContext *context = + gst_gl_display_get_context (glimage_sink->display); + GstGLWindow *window = gst_gl_context_get_window (context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink); @@ -504,6 +509,7 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) gst_gl_window_set_close_callback (window, NULL, NULL, NULL); gst_object_unref (window); + gst_object_unref (context); gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } @@ -692,12 +698,14 @@ 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); + GstGLContext *context = gst_gl_display_get_context (glimage_sink->display); + GstGLWindow *window = gst_gl_context_get_window (context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); + gst_object_unref (context); } gst_buffer_replace (&glimage_sink->stored_buffer, buf); @@ -771,12 +779,15 @@ 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); + GstGLContext *context = + gst_gl_display_get_context (glimage_sink->display); + GstGLWindow *window = gst_gl_context_get_window (context); glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); gst_object_unref (window); + gst_object_unref (context); } gst_glimage_sink_redisplay (glimage_sink, 0, 0, 0, 0, 0, @@ -959,6 +970,7 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink) /* check if a client draw callback is registered */ if (gl_sink->clientDrawCallback) { + gboolean doRedisplay = gl_sink->clientDrawCallback (gl_sink->redisplay_texture, gl_sink->redisplay_texture_width, @@ -966,12 +978,14 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink) gl_sink->client_data); if (doRedisplay) { - GstGLWindow *window = gst_gl_display_get_window (gl_sink->display); + GstGLContext *context = gst_gl_display_get_context (gl_sink->display); + GstGLWindow *window = gst_gl_context_get_window (context); gst_gl_window_draw_unlocked (window, gl_sink->redisplay_texture_width, gl_sink->redisplay_texture_height); gst_object_unref (window); + gst_object_unref (context); } } /* default opengl scene */ @@ -1062,10 +1076,12 @@ 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) { + GstGLContext *context; GstGLWindow *window; gboolean alive; - window = gst_gl_display_get_window (gl_sink->display); + context = gst_gl_display_get_context (gl_sink->display); + window = gst_gl_context_get_window (context); if (window && gst_gl_window_is_running (window)) { @@ -1089,6 +1105,7 @@ gst_glimage_sink_redisplay (GstGLImageSink * gl_sink, GLuint texture, } alive = gst_gl_window_is_running (window); gst_object_unref (window); + gst_object_unref (context); return alive; } diff --git a/gst/gl/gstgltestsrc.c b/gst/gl/gstgltestsrc.c index 00df7f15b2..2f169b8883 100644 --- a/gst/gl/gstgltestsrc.c +++ b/gst/gl/gstgltestsrc.c @@ -561,16 +561,16 @@ gst_gl_test_src_start (GstBaseSrc * basesrc) src->display = gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); else { - GstGLWindow *window; + GstGLContext *context; GError *error = NULL; GST_INFO ("Creating GstGLDisplay"); src->display = gst_gl_display_new (); - window = gst_gl_window_new (src->display); - gst_gl_display_set_window (src->display, window); - gst_object_unref (window); + context = gst_gl_context_new (src->display); + gst_gl_display_set_context (src->display, context); + gst_object_unref (context); - if (!gst_gl_window_create_context (window, 0, &error)) { + if (!gst_gl_context_create (context, 0, &error)) { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE;