From 538643e3c0018c1c8622c018d43fbb22d74d48b5 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 13 Nov 2012 22:12:20 +1100 Subject: [PATCH] [606/906] determine the GL platform to use at runtime - Make GstGLWindow subclassablerather than specified at compile time. - Add GstGLWindowX11 for x11 windows and two subclasses, GstGLWindowX11GLX and GstGLWindwX11EGL for GLX and EGL repectively. (win32 and cocoa ports to come) - Also cleanup GL library detection in configure.ac --- gst-libs/gst/gl/Makefile.am | 24 +- gst-libs/gst/gl/gstgldisplay.c | 21 +- gst-libs/gst/gl/gstglrenderer.h | 103 +++ gst-libs/gst/gl/gstglwindow.c | 303 ++++++++ gst-libs/gst/gl/gstglwindow.h | 114 ++- gst-libs/gst/gl/gstglwindow_x11.c | 1020 ++++++++++++------------- gst-libs/gst/gl/gstglwindow_x11.h | 105 +++ gst-libs/gst/gl/gstglwindow_x11ES2.c | 1012 ------------------------ gst-libs/gst/gl/gstglwindow_x11_egl.c | 271 +++++++ gst-libs/gst/gl/gstglwindow_x11_egl.h | 66 ++ gst-libs/gst/gl/gstglwindow_x11_glx.c | 183 +++++ gst-libs/gst/gl/gstglwindow_x11_glx.h | 64 ++ 12 files changed, 1681 insertions(+), 1605 deletions(-) create mode 100644 gst-libs/gst/gl/gstglrenderer.h create mode 100644 gst-libs/gst/gl/gstglwindow.c create mode 100644 gst-libs/gst/gl/gstglwindow_x11.h delete mode 100644 gst-libs/gst/gl/gstglwindow_x11ES2.c create mode 100644 gst-libs/gst/gl/gstglwindow_x11_egl.c create mode 100644 gst-libs/gst/gl/gstglwindow_x11_egl.h create mode 100644 gst-libs/gst/gl/gstglwindow_x11_glx.c create mode 100644 gst-libs/gst/gl/gstglwindow_x11_glx.h diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am index 4ab64d1aba..1d9688ee5c 100644 --- a/gst-libs/gst/gl/Makefile.am +++ b/gst-libs/gst/gl/Makefile.am @@ -2,8 +2,6 @@ lib_LTLIBRARIES = libgstgl-@GST_API_VERSION@.la EXTRA_DIST = \ - gstglwindow_x11.c \ - gstglwindow_x11ES2.c \ gstglwindow_win32.c \ gstglwindow_winCE.c \ gstglwindow_cocoa.m @@ -17,19 +15,25 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \ gstglshader.c \ gstglshadervariables.c \ gstgldownload.c \ - gstglupload.c + gstglupload.c \ + gstglwindow.c -if GL_BACKEND_WIN32 +#SUBDIRS = +if HAVE_WINDOW_WIN32 libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_win32.c endif -if GL_BACKEND_COCOA +if HAVE_WINDOW_COCOA libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_cocoa.m endif -if GL_BACKEND_X11 +if HAVE_WINDOW_X11 libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_x11.c +if USE_GLX +libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_x11_glx.c endif -if GL_BACKEND_X11ES2 -libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_x11ES2.c +if USE_EGL +libgstgl_@GST_API_VERSION@_la_SOURCES += gstglwindow_x11_egl.c +endif +#SUBDIRS += x11 endif libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl @@ -42,7 +46,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ gstglfilter.h \ gstglmixer.h \ gstglmixerpad.h \ - gstglshadervariables.h \ + gstglshadervariables.h \ gstglshader.h \ gstgldownload.h \ gstglupload.h @@ -62,7 +66,7 @@ libgstgl_@GST_API_VERSION@_la_OBJCFLAGS = \ libgstgl_@GST_API_VERSION@_la_LDFLAGS = \ $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS) -if GL_BACKEND_COCOA +if HAVE_WINDOW_COCOA libgstgl_@GST_API_VERSION@_la_LIBTOOLFLAGS = --tag=OBJC else libgstgl_@GST_API_VERSION@_la_LIBTOOLFLAGS = --tag=CC diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 05ba8b068a..a13f5dd5a2 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -93,8 +93,6 @@ static void gst_gl_display_class_init (GstGLDisplayClass * klass) { G_OBJECT_CLASS (klass)->finalize = gst_gl_display_finalize; - - gst_gl_window_init_platform (); } @@ -217,7 +215,7 @@ gst_gl_display_finalize (GObject * object) GST_INFO ("send quit gl window loop"); - gst_gl_window_quit_loop (display->gl_window, + 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"); @@ -303,7 +301,9 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) GLenum err = GLEW_OK; gst_gl_display_lock (display); - display->gl_window = gst_gl_window_new (display->external_gl_context); + display->gl_window = + gst_gl_window_new (GST_GL_RENDERER_API_OPENGL, + display->external_gl_context); if (!display->gl_window) { gst_gl_display_set_error (display, "Failed to create gl window"); @@ -385,7 +385,7 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) //setup callbacks gst_gl_window_set_resize_callback (display->gl_window, - GST_GL_WINDOW_CB2 (gst_gl_display_on_resize), display); + GST_GL_WINDOW_RESIZE_CB (gst_gl_display_on_resize), display); gst_gl_window_set_draw_callback (display->gl_window, GST_GL_WINDOW_CB (gst_gl_display_on_draw), display); gst_gl_window_set_close_callback (display->gl_window, @@ -395,7 +395,7 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) gst_gl_display_unlock (display); - gst_gl_window_run_loop (display->gl_window); + gst_gl_window_run (display->gl_window); GST_INFO ("loop exited\n"); @@ -1302,10 +1302,10 @@ gst_gl_display_del_shader (GstGLDisplay * display, GstGLShader * shader) /* Called by the glimagesink */ void -gst_gl_display_set_window_id (GstGLDisplay * display, gulong window_id) +gst_gl_display_set_window_id (GstGLDisplay * display, guintptr window_id) { gst_gl_display_lock (display); - gst_gl_window_set_external_window_id (display->gl_window, window_id); + gst_gl_window_set_window_handle (display->gl_window, window_id); gst_gl_display_unlock (display); } @@ -1342,8 +1342,7 @@ 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_internal_gl_context (display->gl_window); + external_gl_context = gst_gl_window_get_gl_context (display->gl_window); gst_gl_display_unlock (display); return external_gl_context; } @@ -1353,7 +1352,7 @@ gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activate) { if (!activate) gst_gl_display_lock (display); - gst_gl_window_activate_gl_context (display->gl_window, activate); + gst_gl_window_activate (display->gl_window, activate); if (activate) gst_gl_display_unlock (display); } diff --git a/gst-libs/gst/gl/gstglrenderer.h b/gst-libs/gst/gl/gstglrenderer.h new file mode 100644 index 0000000000..9e91ccdec0 --- /dev/null +++ b/gst-libs/gst/gl/gstglrenderer.h @@ -0,0 +1,103 @@ +/* + * 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_RENDERER_H__ +#define __GST_GL_RENDERER_H__ + +/* OpenGL 2.0 for Embedded Systems */ +#ifdef GST_GL_RENDERER_GLES2 +# undef UNICODE +# include +# define UNICODE +# include +# include "gstgles2.h" +/* OpenGL for usual systems */ +#endif +#if GST_GL_RENDERER_GL || GST_GL_RENDERER_GL3 +# if __APPLE__ +# include +# include +# include +# else +# if HAVE_GLEW +# include +# endif +# include +# endif +#endif + +#include + +G_BEGIN_DECLS + +#define GST_GL_TYPE_RENDERER (gst_gl_renderer_get_type()) +#define GST_GL_RENDERER(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_RENDERER, GstGLRenderer)) +#define GST_GL_RENDERER_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_RENDERER, GstGLRendererClass)) +#define GST_GL_IS_RENDERER(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_RENDERER)) +#define GST_GL_IS_RENDERER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_RENDERER)) +#define GST_GL_RENDERER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_RENDERER, GstGLRendererClass)) + +#define GST_GL_RENDERER_ERROR (gst_gl_renderer_error_quark ()) + +typedef struct _GstGLRenderer GstGLRenderer; +typedef struct _GstGLRendererPrivate GstGLRendererPrivate; +typedef struct _GstGLRendererClass GstGLRendererClass; + +typedef enum { + GST_GL_RENDERER_API_OPENGL = 1, + GST_GL_RENDERER_API_OPENGL3 = 2, + GST_GL_RENDERER_API_GLES = 40, + GST_GL_RENDERER_API_GLES2 = 41, + GST_GL_RENDERER_API_GLES3 = 42, + + GST_GL_RENDERER_API_LAST = 255 +} GstGLRendererAPI; + +struct _GstGLRenderer { + /*< private >*/ + GObject parent; + + /*< public >*/ + GstGLRendererAPI renderer_api; + + /*< private >*/ + gpointer _reserved[GST_PADDING_LARGE]; +}; + +struct _GstGLRendererClass { + /*< private >*/ + GObjectClass parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING_LARGE]; +}; + +/* methods */ + +GQuark gst_gl_renderer_error_quark (void); +GType gst_gl_renderer_get_type (void); + +GstGLRenderer * gst_gl_renderer_new (); + +GstGLRendererAPI gst_gl_renderer_get_renderer_api (GstGLRenderer *renderer); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_H__ */ diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c new file mode 100644 index 0000000000..a173acc564 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow.c @@ -0,0 +1,303 @@ +/* + * 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. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gstglwindow.h" + +#ifdef HAVE_WINDOW_X11 +#include "gstglwindow_x11.h" +#endif +#ifdef HAVE_WINDOW_WIN32 +#include "win32/gstglwindow_win32.h" +#endif +#ifdef HAVE_WINDOW_COCOA +#include "osx/gstglwindow_cocoa.h" +#endif + +#define GST_CAT_DEFAULT gst_gl_window_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_gl_window_debug, "glwindow", 0, "glwindow element"); +#define gst_gl_window_parent_class parent_class +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT, + DEBUG_INIT); + +static void +gst_gl_window_init (GstGLWindow * window) +{ + g_mutex_init (&window->lock); + window->need_lock = TRUE; +} + +static void +gst_gl_window_class_init (GstGLWindowClass * klass) +{ +} + +GstGLWindow * +gst_gl_window_new (GstGLRendererAPI render_api, guintptr external_gl_context) +{ + GstGLWindow *window = NULL; + const gchar *user_choice; + + user_choice = g_getenv ("GST_GL_WINDOW"); +#ifdef HAVE_WINDOW_X11 + if (!window && (!user_choice || g_strstr_len (user_choice, 3, "x11"))) + window = + GST_GL_WINDOW (gst_gl_window_x11_new (render_api, external_gl_context)); +#endif +#ifdef HAVE_WINDOW_WIN32 + if (!window && (!user_choice || g_strstr_len (user_choice, 5, "win32"))) + window = + GST_GL_WINDOW (gst_gl_window_win32_new (render_api, + external_gl_context)); +#endif +#ifdef HAVE_WINDOW_COCOA + if (!window && (!user_choice || g_strstr_len (user_choice, 5, "cocoa"))) + window = + GST_GL_WINDOW (gst_gl_window_cocoa_new (render_api, + external_gl_context)); +#endif + if (!window) { + GST_WARNING ("could not create a window, user choice:%s", user_choice); + /* FIXME: set and return a GError */ + return NULL; + } + + window->external_gl_context = external_gl_context; + + return window; +} + +GstGLPlatform +gst_gl_window_get_platform (GstGLWindow * window) +{ + GstGLWindowClass *window_class; + + window_class = GST_GL_WINDOW_GET_CLASS (window); + + g_return_val_if_fail (window_class->get_platform != NULL, + GST_GL_PLATFORM_UNKNOWN); + + return window_class->get_platform (window); +} + +guintptr +gst_gl_window_get_gl_context (GstGLWindow * window) +{ + GstGLWindowClass *window_class; + guintptr result; + + g_return_val_if_fail (GST_GL_IS_WINDOW (window), 0); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_val_if_fail (window_class->get_gl_context != NULL, 0); + + GST_GL_WINDOW_LOCK (window); + result = window_class->get_gl_context (window); + GST_GL_WINDOW_UNLOCK (window); + + return result; +} + +gboolean +gst_gl_window_activate (GstGLWindow * window, gboolean activate) +{ + GstGLWindowClass *window_class; + gboolean result; + + 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->activate != NULL, FALSE); + + GST_GL_WINDOW_LOCK (window); + result = window_class->activate (window, activate); + GST_GL_WINDOW_UNLOCK (window); + + return result; +} + +void +gst_gl_window_set_window_handle (GstGLWindow * window, guintptr handle) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_return_if_fail (handle != 0); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->set_window_handle != NULL); + + GST_GL_WINDOW_LOCK (window); + window_class->set_window_handle (window, handle); + GST_GL_WINDOW_UNLOCK (window); +} + +guintptr +gst_gl_window_get_window_handle (GstGLWindow * window) +{ + GstGLWindowClass *window_class; + guintptr result; + + g_return_val_if_fail (GST_GL_IS_WINDOW (window), 0); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_val_if_fail (window_class->get_window_handle != NULL, FALSE); + + GST_GL_WINDOW_LOCK (window); + result = window_class->get_window_handle (window); + GST_GL_WINDOW_UNLOCK (window); + + return result; +} + +void +gst_gl_window_draw_unlocked (GstGLWindow * window, guint width, guint height) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->draw_unlocked != NULL); + + window_class->draw_unlocked (window, width, height); +} + +void +gst_gl_window_draw (GstGLWindow * window, guint width, guint height) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->draw != NULL); + + GST_GL_WINDOW_LOCK (window); + window_class->draw (window, width, height); + GST_GL_WINDOW_UNLOCK (window); +} + +void +gst_gl_window_run (GstGLWindow * window) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->run != NULL); + + GST_GL_WINDOW_LOCK (window); + window_class->run (window); + GST_GL_WINDOW_UNLOCK (window); +} + +void +gst_gl_window_quit (GstGLWindow * window, GstGLWindowCB callback, gpointer data) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->quit != NULL); + + GST_GL_WINDOW_LOCK (window); + + window->close = callback; + window->close_data = data; + window_class->quit (window, callback, data); + + GST_GL_WINDOW_UNLOCK (window); +} + +void +gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback, + gpointer data) +{ + GstGLWindowClass *window_class; + + g_return_if_fail (GST_GL_IS_WINDOW (window)); + g_return_if_fail (callback != NULL); + window_class = GST_GL_WINDOW_GET_CLASS (window); + g_return_if_fail (window_class->quit != NULL); + + GST_GL_WINDOW_LOCK (window); + window_class->send_message (window, callback, data); + GST_GL_WINDOW_UNLOCK (window); +} + +/** + * gst_gl_window_set_need_lock: + * + * window: a #GstGLWindow + * need_lock: whether the @window needs to lock for concurrent access + * + * This API is intended only for subclasses of #GstGLWindow in order to ensure + * correct interaction with the underlying window system. + */ +void +gst_gl_window_set_need_lock (GstGLWindow * window, gboolean need_lock) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + + window->need_lock = need_lock; +} + +void +gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, + gpointer data) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + + GST_GL_WINDOW_LOCK (window); + + window->draw = callback; + window->draw_data = data; + + GST_GL_WINDOW_UNLOCK (window); +} + +void +gst_gl_window_set_resize_callback (GstGLWindow * window, + GstGLWindowResizeCB callback, gpointer data) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + + GST_GL_WINDOW_LOCK (window); + + window->resize = callback; + window->resize_data = data; + + GST_GL_WINDOW_UNLOCK (window); +} + +void +gst_gl_window_set_close_callback (GstGLWindow * window, GstGLWindowCB callback, + gpointer data) +{ + g_return_if_fail (GST_GL_IS_WINDOW (window)); + + GST_GL_WINDOW_LOCK (window); + + window->close = callback; + window->close_data = data; + + GST_GL_WINDOW_UNLOCK (window); +} diff --git a/gst-libs/gst/gl/gstglwindow.h b/gst-libs/gst/gl/gstglwindow.h index bce356053d..541bd1734d 100644 --- a/gst-libs/gst/gl/gstglwindow.h +++ b/gst-libs/gst/gl/gstglwindow.h @@ -21,25 +21,6 @@ #ifndef __GST_GL_WINDOW_H__ #define __GST_GL_WINDOW_H__ -/* OpenGL 2.0 for Embedded Systems */ -#ifdef OPENGL_ES2 -#undef UNICODE -#include -#define UNICODE -#include -#include "gstgles2.h" -/* OpenGL for usual systems */ -#else -#if __APPLE__ -#include -#include -#include -#else -#include -#include -#endif -#endif - #include G_BEGIN_DECLS @@ -51,13 +32,38 @@ G_BEGIN_DECLS #define GST_GL_IS_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW)) #define GST_GL_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW, GstGLWindowClass)) +#define GST_GL_WINDOW_LOCK(w) \ + do { \ + if (GST_GL_WINDOW(w)->need_lock) \ + g_mutex_lock (&GST_GL_WINDOW(w)->lock); \ + } while (0) + +#define GST_GL_WINDOW_UNLOCK(w) \ + do { \ + if (GST_GL_WINDOW(w)->need_lock) \ + g_mutex_unlock (&GST_GL_WINDOW(w)->lock); \ + } while (0) + +#define GST_GL_WINDOW_GET_LOCK(w) (&GST_GL_WINDOW(w)->lock) + #define GST_GL_WINDOW_ERROR (gst_gl_window_error_quark ()) -typedef void (* GstGLWindowCB) ( gpointer ); -typedef void (* GstGLWindowCB2) ( gpointer, gint, gint ); +typedef void (*GstGLWindowCB) (gpointer data); +typedef void (*GstGLWindowResizeCB) (gpointer data, guint width, guint height); #define GST_GL_WINDOW_CB(f) ((GstGLWindowCB) (f)) -#define GST_GL_WINDOW_CB2(f) ((GstGLWindowCB2) (f)) +#define GST_GL_WINDOW_RESIZE_CB(f) ((GstGLWindowResizeCB) (f)) + +typedef enum +{ + GST_GL_PLATFORM_UNKNOWN = 0, + GST_GL_PLATFORM_EGL, + GST_GL_PLATFORM_GLX, + GST_GL_PLATFORM_WGL, + GST_GL_PLATFORM_CGL, + + GST_GL_PLATFORM_LAST = 255 +} GstGLPlatform; typedef struct _GstGLWindow GstGLWindow; typedef struct _GstGLWindowPrivate GstGLWindowPrivate; @@ -66,38 +72,66 @@ typedef struct _GstGLWindowClass GstGLWindowClass; struct _GstGLWindow { /*< private >*/ GObject parent; - GstGLWindowPrivate *priv; + + /*< public >*/ + GMutex lock; + gboolean need_lock; + + guintptr external_gl_context; + + GstGLWindowCB draw; + gpointer draw_data; + GstGLWindowCB close; + gpointer close_data; + GstGLWindowResizeCB resize; + gpointer resize_data; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; }; struct _GstGLWindowClass { /*< private >*/ GObjectClass parent_class; + + guintptr (*get_gl_context) (GstGLWindow *window); + gboolean (*activate) (GstGLWindow *window, gboolean activate); + void (*set_window_handle) (GstGLWindow *window, guintptr id); + guintptr (*get_window_handle) (GstGLWindow *window); + void (*draw_unlocked) (GstGLWindow *window, guint width, guint height); + void (*draw) (GstGLWindow *window, guint width, guint height); + void (*run) (GstGLWindow *window); + void (*quit) (GstGLWindow *window, GstGLWindowCB callback, gpointer data); + void (*send_message) (GstGLWindow *window, GstGLWindowCB callback, gpointer data); + GstGLPlatform (*get_platform) (GstGLWindow *window); + + /*< private >*/ + gpointer _reserved[GST_PADDING]; }; /* methods */ GQuark gst_gl_window_error_quark (void); -GType gst_gl_window_get_type (void); +GType gst_gl_window_get_type (void); -GstGLWindow * gst_gl_window_new (guintptr external_gl_context); +GstGLWindow * gst_gl_window_new (GstGLRendererAPI render_api, guintptr external_gl_context); -guintptr gst_gl_window_get_internal_gl_context (GstGLWindow *window); -void gst_gl_window_activate_gl_context (GstGLWindow *window, gboolean activate); +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); +void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); +void gst_gl_window_set_need_lock (GstGLWindow *window, gboolean need_lock); -void gst_gl_window_set_external_window_id (GstGLWindow *window, guintptr id); -void gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); -void gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback, gpointer data); -void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); +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); +void gst_gl_window_draw (GstGLWindow *window, guint width, guint height); +void gst_gl_window_run (GstGLWindow *window); +void gst_gl_window_quit (GstGLWindow *window, GstGLWindowCB callback, gpointer data); +void gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data); -void gst_gl_window_draw_unlocked (GstGLWindow *window, gint width, gint height); -void gst_gl_window_draw (GstGLWindow *window, gint width, gint height); -void gst_gl_window_run_loop (GstGLWindow *window); -void gst_gl_window_quit_loop (GstGLWindow *window, GstGLWindowCB callback, gpointer data); - -void gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data); - -/* helper */ -void gst_gl_window_init_platform (); +GstGLPlatform gst_gl_window_get_platform (GstGLWindow *window); G_END_DECLS diff --git a/gst-libs/gst/gl/gstglwindow_x11.c b/gst-libs/gst/gl/gstglwindow_x11.c index d0c6657da1..0e9a3d98c2 100644 --- a/gst-libs/gst/gl/gstglwindow_x11.c +++ b/gst-libs/gst/gl/gstglwindow_x11.c @@ -24,19 +24,29 @@ #include "config.h" #endif -#include "gstglwindow.h" - +#include #include -#include +#include "gstglwindow_x11.h" -#define GST_GL_WINDOW_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate)) +#ifdef HAVE_GLX +# include "gstglwindow_x11_glx.h" +#endif +#ifdef HAVE_EGL +# include "gstglwindow_x11_egl.h" +#endif +#define GST_GL_WINDOW_X11_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW_X11, GstGLWindowX11Private)) -/* A gl window is created and deleted in a thread dedicated to opengl calls - The name contains "window" because an opengl context is used in cooperation - with a window */ +#define GST_CAT_DEFAULT gst_gl_window_x11_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow"); +#define gst_gl_window_x11_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGLWindowX11, gst_gl_window_x11, GST_GL_TYPE_WINDOW, + DEBUG_INIT); enum { @@ -44,90 +54,62 @@ enum ARG_DISPLAY }; -struct _GstGLWindowPrivate +struct _GstGLWindowX11Private { - /* X is not thread safe */ - GMutex *x_lock; - GCond *cond_send_message; - gboolean running; - gboolean visible; - gboolean allow_extra_expose_events; - - /* opengl context */ - gchar *display_name; - Display *device; - Screen *screen; - gint screen_num; - Visual *visual; - Window root; - gulong white; - gulong black; - gint depth; - gint device_width; - gint device_height; - gint connection; - XVisualInfo *visual_info; - Window parent; - - /* We use a specific connection to send events */ - Display *disp_send; - - /* X window */ - Window internal_win_id; - GLXContext gl_context; - - /* frozen callbacks */ - GstGLWindowCB draw_cb; - gpointer draw_data; - GstGLWindowCB2 resize_cb; - gpointer resize_data; - GstGLWindowCB close_cb; - gpointer close_data; + gboolean activate; + gboolean activate_result; }; -G_DEFINE_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT); +guintptr gst_gl_window_x11_get_gl_context (GstGLWindow * window); +gboolean gst_gl_window_x11_activate (GstGLWindow * window, gboolean activate); +void gst_gl_window_x11_set_window_handle (GstGLWindow * window, + guintptr handle); +guintptr gst_gl_window_x11_get_window_handle (GstGLWindow * window); +void gst_gl_window_x11_draw_unlocked (GstGLWindow * window, guint width, + guint height); +void gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height); +void gst_gl_window_x11_run (GstGLWindow * window); +void gst_gl_window_x11_quit (GstGLWindow * window, GstGLWindowCB callback, + gpointer data); +void gst_gl_window_x11_send_message (GstGLWindow * window, + GstGLWindowCB callback, gpointer data); -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "GstGLWindow" - -gboolean _gst_gl_window_debug = FALSE; - -void -gst_gl_window_init_platform () -{ -} +static gboolean gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11); /* Must be called in the gl thread */ static void -gst_gl_window_finalize (GObject * object) +gst_gl_window_x11_finalize (GObject * object) { - GstGLWindow *window = GST_GL_WINDOW (object); - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (object); + GstGLWindowX11Class *window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); XEvent event; Bool ret = TRUE; - g_mutex_lock (priv->x_lock); + GST_GL_WINDOW_LOCK (window_x11); - priv->parent = 0; - if (priv->device) { - XUnmapWindow (priv->device, priv->internal_win_id); + window_x11->parent_win = 0; + if (window_x11->device) { + if (window_x11->internal_win_id) + XUnmapWindow (window_x11->device, window_x11->internal_win_id); - ret = glXMakeCurrent (priv->device, None, NULL); + ret = window_class->activate (window_x11, FALSE); if (!ret) - g_debug ("failed to release opengl context\n"); + GST_DEBUG ("failed to release opengl context"); + window_class->destroy_context (window_x11); - glXDestroyContext (priv->device, priv->gl_context); + XFree (window_x11->visual_info); - XFree (priv->visual_info); + if (window_x11->internal_win_id) { + XReparentWindow (window_x11->device, window_x11->internal_win_id, + window_x11->root, 0, 0); + XDestroyWindow (window_x11->device, window_x11->internal_win_id); + } + XSync (window_x11->device, FALSE); - XReparentWindow (priv->device, priv->internal_win_id, priv->root, 0, 0); - XDestroyWindow (priv->device, priv->internal_win_id); - XSync (priv->device, FALSE); + while (XPending (window_x11->device)) + XNextEvent (window_x11->device, &event); - while (XPending (priv->device)) - XNextEvent (priv->device, &event); - - XSetCloseDownMode (priv->device, DestroyAll); + XSetCloseDownMode (window_x11->device, DestroyAll); /*XAddToSaveSet (display, w) Display *display; @@ -139,44 +121,33 @@ gst_gl_window_finalize (GObject * object) //other glimagesink, is not useable and so each opengl call causes a segmentation fault. //Maybe the solution is to use: XAddToSaveSet //The following line is commented to avoid the disagreement explained before. - //XCloseDisplay (priv->device); + //XCloseDisplay (window_x11->device); - g_debug ("display receiver closed\n"); - XCloseDisplay (priv->disp_send); - g_debug ("display sender closed\n"); + GST_DEBUG ("display receiver closed"); + XCloseDisplay (window_x11->disp_send); + GST_DEBUG ("display sender closed"); } - if (priv->cond_send_message) { - g_cond_free (priv->cond_send_message); - priv->cond_send_message = NULL; - } + g_cond_clear (&window_x11->cond_send_message); - g_mutex_unlock (priv->x_lock); + GST_GL_WINDOW_UNLOCK (window_x11); - if (priv->x_lock) { - g_mutex_free (priv->x_lock); - priv->x_lock = NULL; - } - - G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object); + G_OBJECT_CLASS (parent_class)->finalize (object); } static void -gst_gl_window_set_property (GObject * object, guint prop_id, +gst_gl_window_x11_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstGLWindow *window; - GstGLWindowPrivate *priv; + GstGLWindowX11 *window_x11; - g_return_if_fail (GST_GL_IS_WINDOW (object)); + g_return_if_fail (GST_GL_IS_WINDOW_X11 (object)); - window = GST_GL_WINDOW (object); - - priv = window->priv; + window_x11 = GST_GL_WINDOW_X11 (object); switch (prop_id) { case ARG_DISPLAY: - priv->display_name = g_strdup (g_value_get_string (value)); + window_x11->display_name = g_strdup (g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -185,21 +156,18 @@ gst_gl_window_set_property (GObject * object, guint prop_id, } static void -gst_gl_window_get_property (GObject * object, guint prop_id, +gst_gl_window_x11_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstGLWindow *window; - GstGLWindowPrivate *priv; + GstGLWindowX11 *window_x11; - g_return_if_fail (GST_GL_IS_WINDOW (object)); + g_return_if_fail (GST_GL_IS_WINDOW_X11 (object)); - window = GST_GL_WINDOW (object); - - priv = window->priv; + window_x11 = GST_GL_WINDOW_X11 (object); switch (prop_id) { case ARG_DISPLAY: - g_value_set_string (value, priv->display_name); + g_value_set_string (value, window_x11->display_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -208,61 +176,183 @@ gst_gl_window_get_property (GObject * object, guint prop_id, } static void -gst_gl_window_log_handler (const gchar * domain, GLogLevelFlags flags, - const gchar * message, gpointer user_data) -{ - if (_gst_gl_window_debug) { - g_log_default_handler (domain, flags, message, user_data); - } -} - -static void -gst_gl_window_class_init (GstGLWindowClass * klass) +gst_gl_window_x11_class_init (GstGLWindowX11Class * klass) { GObjectClass *obj_class = G_OBJECT_CLASS (klass); + GstGLWindowClass *window_class = (GstGLWindowClass *) klass; - g_type_class_add_private (klass, sizeof (GstGLWindowPrivate)); + g_type_class_add_private (klass, sizeof (GstGLWindowX11Private)); - obj_class->finalize = gst_gl_window_finalize; - obj_class->set_property = gst_gl_window_set_property; - obj_class->get_property = gst_gl_window_get_property; + obj_class->finalize = gst_gl_window_x11_finalize; + obj_class->set_property = gst_gl_window_x11_set_property; + obj_class->get_property = gst_gl_window_x11_get_property; g_object_class_install_property (obj_class, ARG_DISPLAY, g_param_spec_string ("display", "Display", "X Display name", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + window_class->get_gl_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_get_gl_context); + window_class->activate = GST_DEBUG_FUNCPTR (gst_gl_window_x11_activate); + window_class->set_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_set_window_handle); + window_class->get_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_get_window_handle); + window_class->draw_unlocked = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_draw_unlocked); + window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_x11_draw); + window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_x11_run); + window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_x11_quit); + window_class->send_message = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_send_message); } static void -gst_gl_window_init (GstGLWindow * window) +gst_gl_window_x11_init (GstGLWindowX11 * window) { - window->priv = GST_GL_WINDOW_GET_PRIVATE (window); - - if (g_getenv ("GST_GL_WINDOW_DEBUG") != NULL) - _gst_gl_window_debug = TRUE; - - g_log_set_handler ("GstGLWindow", G_LOG_LEVEL_DEBUG, - gst_gl_window_log_handler, NULL); + window->priv = GST_GL_WINDOW_X11_GET_PRIVATE (window); } /* Must be called in the gl thread */ -GstGLWindow * -gst_gl_window_new (gulong external_gl_context) +GstGLWindowX11 * +gst_gl_window_x11_new (GstGLRendererAPI render_api, + guintptr external_gl_context) { - GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL); - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window = NULL; + const gchar *user_choice; + gboolean user_glx; + gboolean user_egl; - gint attrib[] = { - GLX_RGBA, - GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, - GLX_DEPTH_SIZE, 16, - GLX_DOUBLEBUFFER, - None - }; + user_choice = g_getenv ("GST_GL_PLATFORM"); + user_glx = !user_choice || g_strstr_len (user_choice, 3, "glx") != NULL; + user_egl = !user_choice || g_strstr_len (user_choice, 3, "egl") != NULL; - Bool ret = FALSE; - gint error_base; - gint event_base; +#ifdef HAVE_GLX +#ifdef HAVE_EGL + /* try GLX first for Desktop OpenGL */ + if (render_api == GST_GL_RENDERER_API_OPENGL + || render_api == GST_GL_RENDERER_API_OPENGL3) { + if (!window && user_glx) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_glx_new (render_api, + external_gl_context)); + if (!window && user_egl) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_egl_new (render_api, + external_gl_context)); + } else { /* try EGL first for OpenGL|ES */ + if (!window && user_egl) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_egl_new (render_api, + external_gl_context)); + if (!window && user_glx) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_glx_new (render_api, + external_gl_context)); + } +#endif /* HAVE_EGL */ + if (!window && user_glx) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_glx_new (render_api, + external_gl_context)); +#endif /* HAVE_GLX */ +#ifdef HAVE_EGL + if (!window && user_egl) + window = + GST_GL_WINDOW_X11 (gst_gl_window_x11_egl_new (render_api, + external_gl_context)); +#endif /* HAVE_EGL */ + if (!window) { + GST_WARNING ("Failed to create x11 window, user_choice:%s", + user_choice ? user_choice : "NULL"); + return NULL; + } + return window; +} + +gboolean +gst_gl_window_x11_open_device (GstGLWindowX11 * window_x11, + GstGLRendererAPI render_api, guintptr external_gl_context) +{ + GstGLWindowX11Class *window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); + + setlocale (LC_NUMERIC, "C"); + + gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), TRUE); + + GST_GL_WINDOW_LOCK (window_x11); + + g_cond_init (&window_x11->cond_send_message); + window_x11->running = TRUE; + window_x11->visible = FALSE; + window_x11->parent_win = 0; + window_x11->allow_extra_expose_events = TRUE; + + window_x11->device = XOpenDisplay (window_x11->display_name); + if (window_x11->device == NULL) { + GST_WARNING ("Failed to open X display"); + goto failure; + } + + XSynchronize (window_x11->device, FALSE); + + GST_LOG ("gl device id: %ld", (gulong) window_x11->device); + + window_x11->disp_send = XOpenDisplay (window_x11->display_name); + + XSynchronize (window_x11->disp_send, FALSE); + + GST_LOG ("gl display sender: %ld", (gulong) window_x11->disp_send); + + window_x11->screen = DefaultScreenOfDisplay (window_x11->device); + window_x11->screen_num = DefaultScreen (window_x11->device); + window_x11->visual = + DefaultVisual (window_x11->device, window_x11->screen_num); + window_x11->root = DefaultRootWindow (window_x11->device); + window_x11->white = XWhitePixel (window_x11->device, window_x11->screen_num); + window_x11->black = XBlackPixel (window_x11->device, window_x11->screen_num); + window_x11->depth = DefaultDepthOfScreen (window_x11->screen); + + GST_LOG ("gl root id: %lud", (gulong) window_x11->root); + + window_x11->device_width = + DisplayWidth (window_x11->device, window_x11->screen_num); + window_x11->device_height = + DisplayHeight (window_x11->device, window_x11->screen_num); + + window_x11->connection = ConnectionNumber (window_x11->device); + + if (!window_class->choose_visual (window_x11)) { + GST_WARNING ("Failed to choose XVisual"); + goto failure; + } + + gst_gl_window_x11_create_window (window_x11); + + if (!window_class->create_context (window_x11, render_api, + external_gl_context)) { + GST_WARNING ("Failed to create context"); + goto failure; + } + + if (!window_class->activate (window_x11, TRUE)) { + GST_WARNING ("failed to make context current"); + goto failure; + } + + GST_GL_WINDOW_UNLOCK (window_x11); + + return TRUE; + +failure: + GST_GL_WINDOW_UNLOCK (window_x11); + return FALSE; +} + +static gboolean +gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11) +{ XSetWindowAttributes win_attr; XTextProperty text_property; XWMHints wm_hints; @@ -273,77 +363,24 @@ gst_gl_window_new (gulong external_gl_context) static gint x = 0; static gint y = 0; - setlocale (LC_NUMERIC, "C"); + if (window_x11->visual_info->visual != window_x11->visual) + GST_LOG ("selected visual is different from the default"); - priv->x_lock = g_mutex_new (); - priv->cond_send_message = g_cond_new (); - priv->running = TRUE; - priv->visible = FALSE; - priv->parent = 0; - priv->allow_extra_expose_events = TRUE; + if (window_x11->visual_info->class == TrueColor) + GST_LOG ("visual is using TrueColor"); - g_mutex_lock (priv->x_lock); - - priv->device = XOpenDisplay (priv->display_name); - if (priv->device == NULL) { - g_debug ("XOpenDisplay failed\n"); - goto failure; - } - - XSynchronize (priv->device, FALSE); - - g_debug ("gl device id: %ld\n", (gulong) priv->device); - - priv->disp_send = XOpenDisplay (priv->display_name); - - XSynchronize (priv->disp_send, FALSE); - - g_debug ("gl display sender: %ld\n", (gulong) priv->disp_send); - - priv->screen = DefaultScreenOfDisplay (priv->device); - priv->screen_num = DefaultScreen (priv->device); - priv->visual = DefaultVisual (priv->device, priv->screen_num); - priv->root = DefaultRootWindow (priv->device); - priv->white = XWhitePixel (priv->device, priv->screen_num); - priv->black = XBlackPixel (priv->device, priv->screen_num); - priv->depth = DefaultDepthOfScreen (priv->screen); - - g_debug ("gl root id: %lud\n", (gulong) priv->root); - - priv->device_width = DisplayWidth (priv->device, priv->screen_num); - priv->device_height = DisplayHeight (priv->device, priv->screen_num); - - priv->connection = ConnectionNumber (priv->device); - - ret = glXQueryExtension (priv->device, &error_base, &event_base); - if (!ret) { - g_debug ("No GLX extension\n"); - goto failure; - } - - priv->visual_info = glXChooseVisual (priv->device, priv->screen_num, attrib); - - if (!priv->visual_info) { - g_debug ("glx visual is null (bad attributes)\n"); - goto failure; - } - - if (priv->visual_info->visual != priv->visual) - g_debug ("selected visual is different from the default\n"); - - if (priv->visual_info->class == TrueColor) - g_debug ("visual is using TrueColor\n"); - - g_debug ("visual ID: %d\n", - (gint) XVisualIDFromVisual (priv->visual_info->visual)); - g_debug ("visual info screen: %d\n", priv->visual_info->screen); - g_debug ("visual info visualid: %d\n", (gint) priv->visual_info->visualid); - g_debug ("visual info depth: %d\n", priv->visual_info->depth); - g_debug ("visual info class: %d\n", priv->visual_info->class); - g_debug ("visual info red_mask: %ld\n", priv->visual_info->red_mask); - g_debug ("visual info green_mask: %ld\n", priv->visual_info->green_mask); - g_debug ("visual info blue_mask: %ld\n", priv->visual_info->blue_mask); - g_debug ("visual info bits_per_rgb: %d\n", priv->visual_info->bits_per_rgb); + GST_LOG ("visual ID: %d", + (gint) XVisualIDFromVisual (window_x11->visual_info->visual)); + GST_LOG ("visual info screen: %d", window_x11->visual_info->screen); + GST_LOG ("visual info visualid: %d", + (gint) window_x11->visual_info->visualid); + GST_LOG ("visual info depth: %d", window_x11->visual_info->depth); + GST_LOG ("visual info class: %d", window_x11->visual_info->class); + GST_LOG ("visual info red_mask: %ld", window_x11->visual_info->red_mask); + GST_LOG ("visual info green_mask: %ld", window_x11->visual_info->green_mask); + GST_LOG ("visual info blue_mask: %ld", window_x11->visual_info->blue_mask); + GST_LOG ("visual info bits_per_rgb: %d", + window_x11->visual_info->bits_per_rgb); win_attr.event_mask = StructureNotifyMask | ExposureMask | VisibilityChangeMask; @@ -354,53 +391,42 @@ gst_gl_window_new (gulong external_gl_context) win_attr.border_pixel = 0; win_attr.colormap = - XCreateColormap (priv->device, priv->root, priv->visual_info->visual, - AllocNone); + XCreateColormap (window_x11->device, window_x11->root, + window_x11->visual_info->visual, AllocNone); mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; x += 20; y += 20; - priv->internal_win_id = XCreateWindow (priv->device, priv->root, x, y, - 1, 1, 0, priv->visual_info->depth, InputOutput, - priv->visual_info->visual, mask, &win_attr); + window_x11->internal_win_id = + XCreateWindow (window_x11->device, window_x11->root, x, y, 1, 1, 0, + window_x11->visual_info->depth, InputOutput, + window_x11->visual_info->visual, mask, &win_attr); - XSync (priv->device, FALSE); + XSync (window_x11->device, FALSE); - XSetWindowBackgroundPixmap (priv->device, priv->internal_win_id, None); + XSetWindowBackgroundPixmap (window_x11->device, window_x11->internal_win_id, + None); - g_debug ("gl window id: %lud\n", (gulong) priv->internal_win_id); + GST_LOG ("gl window id: %lud", (gulong) window_x11->internal_win_id); - g_debug ("gl window props: x:%d y:%d\n", x, y); + GST_LOG ("gl window props: x:%d y:%d", x, y); - wm_atoms[0] = XInternAtom (priv->device, "WM_DELETE_WINDOW", True); + wm_atoms[0] = XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True); if (wm_atoms[0] == None) - g_debug ("Cannot create WM_DELETE_WINDOW\n"); + GST_DEBUG ("Cannot create WM_DELETE_WINDOW"); - wm_atoms[1] = XInternAtom (priv->device, "WM_GL_WINDOW", False); + wm_atoms[1] = XInternAtom (window_x11->device, "WM_GL_WINDOW", False); if (wm_atoms[1] == None) - g_debug ("Cannot create WM_GL_WINDOW\n"); + GST_DEBUG ("Cannot create WM_GL_WINDOW"); - wm_atoms[2] = XInternAtom (priv->device, "WM_QUIT_LOOP", False); + wm_atoms[2] = XInternAtom (window_x11->device, "WM_QUIT_LOOP", False); if (wm_atoms[2] == None) - g_debug ("Cannot create WM_QUIT_LOOP\n"); + GST_DEBUG ("Cannot create WM_QUIT_LOOP"); - XSetWMProtocols (priv->device, priv->internal_win_id, wm_atoms, 2); - - priv->gl_context = - glXCreateContext (priv->device, priv->visual_info, - (GLXContext) external_gl_context, TRUE); - - if (!priv->gl_context) { - g_debug ("failed to create opengl context\n"); - goto failure; - } - - g_debug ("gl context id: %ld\n", (gulong) priv->gl_context); - - if (!glXIsDirect (priv->device, priv->gl_context)) - g_debug ("direct rendering failed\n"); + XSetWMProtocols (window_x11->device, window_x11->internal_win_id, wm_atoms, + 2); wm_hints.flags = StateHint; wm_hints.initial_state = NormalState; @@ -408,317 +434,255 @@ gst_gl_window_new (gulong external_gl_context) XStringListToTextProperty ((char **) &title, 1, &text_property); - XSetWMProperties (priv->device, priv->internal_win_id, &text_property, - &text_property, 0, 0, NULL, &wm_hints, NULL); + XSetWMProperties (window_x11->device, window_x11->internal_win_id, + &text_property, &text_property, 0, 0, NULL, &wm_hints, NULL); XFree (text_property.value); - ret = glXMakeCurrent (priv->device, priv->internal_win_id, priv->gl_context); - - if (!ret) { - g_debug ("failed to make opengl context current\n"); - goto failure; - } - - if (glXIsDirect (priv->device, priv->gl_context)) - g_debug ("Direct Rendering: yes\n"); - else - g_debug ("Direct Rendering: no\n"); - - g_mutex_unlock (priv->x_lock); - - return window; - -failure: - g_mutex_unlock (priv->x_lock); - g_object_unref (G_OBJECT (window)); - return NULL; + return TRUE; } -GQuark -gst_gl_window_error_quark (void) +guintptr +gst_gl_window_x11_get_gl_context (GstGLWindow * window) { - return g_quark_from_static_string ("gst-gl-window-error"); + GstGLWindowX11Class *window_class; + + window_class = GST_GL_WINDOW_X11_GET_CLASS (window); + + return window_class->get_gl_context (GST_GL_WINDOW_X11 (window)); } -gulong -gst_gl_window_get_internal_gl_context (GstGLWindow * window) +guintptr +gst_gl_window_x11_get_window_handle (GstGLWindow * window) { - GstGLWindowPrivate *priv = window->priv; - return (gulong) priv->gl_context; + return (guintptr) GST_GL_WINDOW_X11 (window)->internal_win_id; } -void -callback_activate_gl_context (GstGLWindowPrivate * priv) +static void +callback_activate (GstGLWindow * window) { - if (!glXMakeCurrent (priv->device, priv->internal_win_id, priv->gl_context)) - g_debug ("failed to activate opengl context %lud\n", - (gulong) priv->gl_context); + GstGLWindowX11Class *window_class; + GstGLWindowX11Private *priv; + GstGLWindowX11 *window_x11; + + window_x11 = GST_GL_WINDOW_X11 (window); + window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); + priv = window_x11->priv; + + priv->activate_result = window_class->activate (window_x11, priv->activate); } -void -callback_inactivate_gl_context (GstGLWindowPrivate * priv) +gboolean +gst_gl_window_x11_activate (GstGLWindow * window, gboolean activate) { - if (!glXMakeCurrent (priv->device, None, NULL)) - g_debug ("failed to inactivate opengl context %lud\n", - (gulong) priv->gl_context); -} + GstGLWindowX11 *window_x11; + GstGLWindowX11Private *priv; -void -gst_gl_window_activate_gl_context (GstGLWindow * window, gboolean activate) -{ - GstGLWindowPrivate *priv = window->priv; - if (activate) - gst_gl_window_send_message (window, - GST_GL_WINDOW_CB (callback_activate_gl_context), priv); - else - gst_gl_window_send_message (window, - GST_GL_WINDOW_CB (callback_inactivate_gl_context), priv); + window_x11 = GST_GL_WINDOW_X11 (window); + priv = window_x11->priv; + priv->activate = activate; + + gst_gl_window_x11_send_message (window, GST_GL_WINDOW_CB (callback_activate), + window_x11); + + return priv->activate_result; } /* Not called by the gl thread */ void -gst_gl_window_set_external_window_id (GstGLWindow * window, gulong id) +gst_gl_window_x11_set_window_handle (GstGLWindow * window, guintptr id) { - if (window) { - GstGLWindowPrivate *priv = window->priv; - XWindowAttributes attr; + GstGLWindowX11 *window_x11; + XWindowAttributes attr; - g_mutex_lock (priv->x_lock); + window_x11 = GST_GL_WINDOW_X11 (window); - priv->parent = (Window) id; + window_x11->parent_win = (Window) id; - g_debug ("set parent window id: %lud\n", id); + GST_LOG ("set parent window id: %lud", id); - XGetWindowAttributes (priv->disp_send, priv->parent, &attr); + XGetWindowAttributes (window_x11->disp_send, window_x11->parent_win, &attr); - XResizeWindow (priv->disp_send, priv->internal_win_id, attr.width, - attr.height); + XResizeWindow (window_x11->disp_send, window_x11->internal_win_id, attr.width, + attr.height); - XReparentWindow (priv->disp_send, priv->internal_win_id, priv->parent, - 0, 0); + XReparentWindow (window_x11->disp_send, window_x11->internal_win_id, + window_x11->parent_win, 0, 0); - XSync (priv->disp_send, FALSE); - - g_mutex_unlock (priv->x_lock); - } -} - -void -gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->draw_cb = callback; - priv->draw_data = data; - - g_mutex_unlock (priv->x_lock); -} - -void -gst_gl_window_set_resize_callback (GstGLWindow * window, - GstGLWindowCB2 callback, gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->resize_cb = callback; - priv->resize_data = data; - - g_mutex_unlock (priv->x_lock); -} - -void -gst_gl_window_set_close_callback (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->close_cb = callback; - priv->close_data = data; - - g_mutex_unlock (priv->x_lock); + XSync (window_x11->disp_send, FALSE); } /* Called in the gl thread */ void -gst_gl_window_draw_unlocked (GstGLWindow * window, gint width, gint height) +gst_gl_window_x11_draw_unlocked (GstGLWindow * window, guint width, + guint height) { - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11; - if (priv->running && priv->allow_extra_expose_events) { + window_x11 = GST_GL_WINDOW_X11 (window); + + if (window_x11->running && window_x11->allow_extra_expose_events) { XEvent event; XWindowAttributes attr; - XGetWindowAttributes (priv->device, priv->internal_win_id, &attr); + XGetWindowAttributes (window_x11->device, window_x11->internal_win_id, + &attr); event.xexpose.type = Expose; event.xexpose.send_event = TRUE; - event.xexpose.display = priv->device; - event.xexpose.window = priv->internal_win_id; + event.xexpose.display = window_x11->device; + event.xexpose.window = window_x11->internal_win_id; event.xexpose.x = attr.x; event.xexpose.y = attr.y; event.xexpose.width = attr.width; event.xexpose.height = attr.height; event.xexpose.count = 0; - XSendEvent (priv->device, priv->internal_win_id, FALSE, ExposureMask, - &event); - XSync (priv->disp_send, FALSE); + XSendEvent (window_x11->device, window_x11->internal_win_id, FALSE, + ExposureMask, &event); + XSync (window_x11->disp_send, FALSE); } } /* Not called by the gl thread */ void -gst_gl_window_draw (GstGLWindow * window, gint width, gint height) +gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height) { - if (window) { - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11; - g_mutex_lock (priv->x_lock); + window_x11 = GST_GL_WINDOW_X11 (window); - if (priv->running) { - XEvent event; - XWindowAttributes attr; + if (window_x11->running) { + XEvent event; + XWindowAttributes attr; - XGetWindowAttributes (priv->disp_send, priv->internal_win_id, &attr); + XGetWindowAttributes (window_x11->disp_send, window_x11->internal_win_id, + &attr); - if (!priv->visible) { + if (!window_x11->visible) { - if (!priv->parent) { - attr.width = width; - attr.height = height; - XResizeWindow (priv->disp_send, priv->internal_win_id, - attr.width, attr.height); - XSync (priv->disp_send, FALSE); - } - - XMapWindow (priv->disp_send, priv->internal_win_id); - priv->visible = TRUE; + if (!window_x11->parent_win) { + attr.width = width; + attr.height = height; + XResizeWindow (window_x11->disp_send, window_x11->internal_win_id, + attr.width, attr.height); + XSync (window_x11->disp_send, FALSE); } - if (priv->parent) { - XWindowAttributes attr_parent; - XGetWindowAttributes (priv->disp_send, priv->parent, &attr_parent); - - if (attr.width != attr_parent.width || - attr.height != attr_parent.height) { - XMoveResizeWindow (priv->disp_send, priv->internal_win_id, - 0, 0, attr_parent.width, attr_parent.height); - XSync (priv->disp_send, FALSE); - - attr.width = attr_parent.width; - attr.height = attr_parent.height; - - g_debug ("parent resize: %d, %d\n", - attr_parent.width, attr_parent.height); - } - } - - event.xexpose.type = Expose; - event.xexpose.send_event = TRUE; - event.xexpose.display = priv->disp_send; - event.xexpose.window = priv->internal_win_id; - event.xexpose.x = attr.x; - event.xexpose.y = attr.y; - event.xexpose.width = attr.width; - event.xexpose.height = attr.height; - event.xexpose.count = 0; - - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, ExposureMask, - &event); - XSync (priv->disp_send, FALSE); + XMapWindow (window_x11->disp_send, window_x11->internal_win_id); + window_x11->visible = TRUE; } - g_mutex_unlock (priv->x_lock); + if (window_x11->parent_win) { + XWindowAttributes attr_parent; + XGetWindowAttributes (window_x11->disp_send, window_x11->parent_win, + &attr_parent); + + if (attr.width != attr_parent.width || attr.height != attr_parent.height) { + XMoveResizeWindow (window_x11->disp_send, window_x11->internal_win_id, + 0, 0, attr_parent.width, attr_parent.height); + XSync (window_x11->disp_send, FALSE); + + attr.width = attr_parent.width; + attr.height = attr_parent.height; + + GST_LOG ("parent resize: %d, %d", + attr_parent.width, attr_parent.height); + } + } + + event.xexpose.type = Expose; + event.xexpose.send_event = TRUE; + event.xexpose.display = window_x11->disp_send; + event.xexpose.window = window_x11->internal_win_id; + event.xexpose.x = attr.x; + event.xexpose.y = attr.y; + event.xexpose.width = attr.width; + event.xexpose.height = attr.height; + event.xexpose.count = 0; + + XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE, + ExposureMask, &event); + XSync (window_x11->disp_send, FALSE); } } /* Called in the gl thread */ void -gst_gl_window_run_loop (GstGLWindow * window) +gst_gl_window_x11_run (GstGLWindow * window) { - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11; + GstGLWindowX11Class *window_class; - g_debug ("begin loop\n"); + window_x11 = GST_GL_WINDOW_X11 (window); + window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); - g_mutex_lock (priv->x_lock); + GST_DEBUG ("begin loop"); - while (priv->running) { + while (window_x11->running) { XEvent event; XEvent pending_event; - g_mutex_unlock (priv->x_lock); + GST_GL_WINDOW_UNLOCK (window); /* XSendEvent (which are called in other threads) are done from another display structure */ - XNextEvent (priv->device, &event); + XNextEvent (window_x11->device, &event); - g_mutex_lock (priv->x_lock); + GST_GL_WINDOW_LOCK (window); // use in generic/cube and other related uses - priv->allow_extra_expose_events = XPending (priv->device) <= 0; + window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2; switch (event.type) { case ClientMessage: { - Atom wm_delete = XInternAtom (priv->device, "WM_DELETE_WINDOW", True); - Atom wm_gl = XInternAtom (priv->device, "WM_GL_WINDOW", True); - Atom wm_quit_loop = XInternAtom (priv->device, "WM_QUIT_LOOP", True); + Atom wm_delete = + XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True); + Atom wm_gl = XInternAtom (window_x11->device, "WM_GL_WINDOW", True); + Atom wm_quit_loop = + XInternAtom (window_x11->device, "WM_QUIT_LOOP", True); if (wm_delete == None) - g_debug ("Cannot create WM_DELETE_WINDOW\n"); + GST_DEBUG ("Cannot create WM_DELETE_WINDOW"); if (wm_gl == None) - g_debug ("Cannot create WM_GL_WINDOW\n"); + GST_DEBUG ("Cannot create WM_GL_WINDOW"); if (wm_quit_loop == None) - g_debug ("Cannot create WM_QUIT_LOOP\n"); + GST_DEBUG ("Cannot create WM_QUIT_LOOP"); /* Message sent with gst_gl_window_send_message */ if (wm_gl != None && event.xclient.message_type == wm_gl) { - if (priv->running) { + if (window_x11->running) { #if SIZEOF_VOID_P == 8 GstGLWindowCB custom_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); + (GstGLWindowCB) (((event.xclient. + data.l[0] & 0xffffffff) << 32) | (event.xclient. + data.l[1] & 0xffffffff)); gpointer custom_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); + (gpointer) (((event.xclient. + data.l[2] & 0xffffffff) << 32) | (event.xclient. + data.l[3] & 0xffffffff)); #else GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0]; gpointer custom_data = (gpointer) event.xclient.data.l[1]; #endif if (!custom_cb || !custom_data) - g_debug ("custom cb not initialized\n"); + GST_DEBUG ("custom cb not initialized"); custom_cb (custom_data); } - g_cond_signal (priv->cond_send_message); + g_cond_signal (&window_x11->cond_send_message); } /* User clicked on the cross */ else if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) { - g_debug ("Close %lud\n", (gulong) priv->internal_win_id); + GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id); - if (priv->close_cb) - priv->close_cb (priv->close_data); - - priv->draw_cb = NULL; - priv->draw_data = NULL; - priv->resize_cb = NULL; - priv->resize_data = NULL; - priv->close_cb = NULL; - priv->close_data = NULL; + if (window->close) + window->close (window->close_data); } /* message sent with gst_gl_window_quit_loop */ @@ -726,78 +690,78 @@ gst_gl_window_run_loop (GstGLWindow * window) && event.xclient.message_type == wm_quit_loop) { #if SIZEOF_VOID_P == 8 GstGLWindowCB destroy_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); + (GstGLWindowCB) (((event.xclient. + data.l[0] & 0xffffffff) << 32) | (event.xclient. + data.l[1] & 0xffffffff)); gpointer destroy_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); + (gpointer) (((event.xclient. + data.l[2] & 0xffffffff) << 32) | (event.xclient. + data.l[3] & 0xffffffff)); #else GstGLWindowCB destroy_cb = (GstGLWindowCB) event.xclient.data.l[0]; gpointer destroy_data = (gpointer) event.xclient.data.l[1]; #endif - g_debug ("Quit loop message %lud\n", (gulong) priv->internal_win_id); + GST_DEBUG ("Quit loop message %lud", + (gulong) window_x11->internal_win_id); /* exit loop */ - priv->running = FALSE; + window_x11->running = FALSE; /* make sure last pendings send message calls are executed */ - XFlush (priv->device); - while (XCheckTypedEvent (priv->device, ClientMessage, &pending_event)) { + XFlush (window_x11->device); + while (XCheckTypedEvent (window_x11->device, ClientMessage, + &pending_event)) { #if SIZEOF_VOID_P == 8 GstGLWindowCB custom_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); + (GstGLWindowCB) (((event.xclient. + data.l[0] & 0xffffffff) << 32) | (event.xclient. + data.l[1] & 0xffffffff)); gpointer custom_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); + (gpointer) (((event.xclient. + data.l[2] & 0xffffffff) << 32) | (event.xclient. + data.l[3] & 0xffffffff)); #else GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0]; gpointer custom_data = (gpointer) event.xclient.data.l[1]; #endif - g_debug ("execute last pending custom x events\n"); + GST_DEBUG ("execute last pending custom x events"); if (!custom_cb || !custom_data) - g_debug ("custom cb not initialized\n"); + GST_DEBUG ("custom cb not initialized"); custom_cb (custom_data); - g_cond_signal (priv->cond_send_message); + g_cond_signal (&window_x11->cond_send_message); } /* Finally we can destroy opengl ressources (texture/shaders/fbo) */ if (!destroy_cb || !destroy_data) - g_debug ("destroy cb not correclty set\n"); + GST_DEBUG ("destroy cb not correctly set"); destroy_cb (destroy_data); } else - g_debug ("client message not reconized \n"); + GST_DEBUG ("client message not recognized"); break; } case CreateNotify: case ConfigureNotify: { - if (priv->resize_cb) - priv->resize_cb (priv->resize_data, event.xconfigure.width, + if (window->resize) + window->resize (window->resize_data, event.xconfigure.width, event.xconfigure.height); break; } case DestroyNotify: - g_debug ("DestroyNotify\n"); break; case Expose: - if (priv->draw_cb) { - priv->draw_cb (priv->draw_data); - glFlush (); - glXSwapBuffers (priv->device, priv->internal_win_id); + if (window->draw) { + window->draw (window->draw_data); + window_class->swap_buffers (window_x11); } break; @@ -805,20 +769,20 @@ gst_gl_window_run_loop (GstGLWindow * window) { switch (event.xvisibility.state) { case VisibilityUnobscured: - if (priv->draw_cb) - priv->draw_cb (priv->draw_data); + if (window->draw) + window->draw (window->draw_data); break; case VisibilityPartiallyObscured: - if (priv->draw_cb) - priv->draw_cb (priv->draw_data); + if (window->draw) + window->draw (window->draw_data); break; case VisibilityFullyObscured: break; default: - g_debug ("unknown xvisibility event: %d\n", + GST_DEBUG ("unknown xvisibility event: %d", event.xvisibility.state); break; } @@ -826,95 +790,87 @@ gst_gl_window_run_loop (GstGLWindow * window) } default: - g_debug ("unknown XEvent type: %ud\n", event.type); + GST_DEBUG ("unknown XEvent type: %ud", event.type); break; } // switch - } // while running - g_mutex_unlock (priv->x_lock); - - g_debug ("end loop\n"); + GST_DEBUG ("end loop"); } /* Not called by the gl thread */ void -gst_gl_window_quit_loop (GstGLWindow * window, GstGLWindowCB callback, +gst_gl_window_x11_quit (GstGLWindow * window, GstGLWindowCB callback, gpointer data) { - if (window) { - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11; - g_mutex_lock (priv->x_lock); + window_x11 = GST_GL_WINDOW_X11 (window); - if (priv->running) { - XEvent event; + GST_DEBUG ("sending quit, running:%i", window_x11->running); - event.xclient.type = ClientMessage; - event.xclient.send_event = TRUE; - event.xclient.display = priv->disp_send; - event.xclient.window = priv->internal_win_id; - event.xclient.message_type = - XInternAtom (priv->disp_send, "WM_QUIT_LOOP", True);; - event.xclient.format = 32; + if (window_x11->running) { + XEvent event; + + event.xclient.type = ClientMessage; + event.xclient.send_event = TRUE; + event.xclient.display = window_x11->disp_send; + event.xclient.window = window_x11->internal_win_id; + event.xclient.message_type = + XInternAtom (window_x11->disp_send, "WM_QUIT_LOOP", True); + event.xclient.format = 32; #if SIZEOF_VOID_P == 8 - event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; - event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; - event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; - event.xclient.data.l[3] = (((long) data)) & 0xffffffff; + event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; + event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; + event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; + event.xclient.data.l[3] = (((long) data)) & 0xffffffff; #else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; + event.xclient.data.l[0] = (long) callback; + event.xclient.data.l[1] = (long) data; #endif - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, NoEventMask, - &event); - XSync (priv->disp_send, FALSE); - } - - g_mutex_unlock (priv->x_lock); + XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE, + NoEventMask, &event); + XSync (window_x11->disp_send, FALSE); } } /* Not called by the gl thread */ void -gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback, +gst_gl_window_x11_send_message (GstGLWindow * window, GstGLWindowCB callback, gpointer data) { - if (window) { - GstGLWindowPrivate *priv = window->priv; + GstGLWindowX11 *window_x11; - g_mutex_lock (priv->x_lock); + window_x11 = GST_GL_WINDOW_X11 (window); - if (priv->running) { - XEvent event; + if (window_x11->running) { + XEvent event; - event.xclient.type = ClientMessage; - event.xclient.send_event = TRUE; - event.xclient.display = priv->disp_send; - event.xclient.window = priv->internal_win_id; - event.xclient.message_type = - XInternAtom (priv->disp_send, "WM_GL_WINDOW", True); - event.xclient.format = 32; + event.xclient.type = ClientMessage; + event.xclient.send_event = TRUE; + event.xclient.display = window_x11->disp_send; + event.xclient.window = window_x11->internal_win_id; + event.xclient.message_type = + XInternAtom (window_x11->disp_send, "WM_GL_WINDOW", True); + event.xclient.format = 32; #if SIZEOF_VOID_P == 8 - event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; - event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; - event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; - event.xclient.data.l[3] = (((long) data)) & 0xffffffff; + event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; + event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; + event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; + event.xclient.data.l[3] = (((long) data)) & 0xffffffff; #else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; + event.xclient.data.l[0] = (long) callback; + event.xclient.data.l[1] = (long) data; #endif - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, NoEventMask, - &event); - XSync (priv->disp_send, FALSE); + XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE, + NoEventMask, &event); + XSync (window_x11->disp_send, FALSE); - /* block until opengl calls have been executed in the gl thread */ - g_cond_wait (priv->cond_send_message, priv->x_lock); - } - - g_mutex_unlock (priv->x_lock); + /* block until opengl calls have been executed in the gl thread */ + g_cond_wait (&window_x11->cond_send_message, + GST_GL_WINDOW_GET_LOCK (window)); } } diff --git a/gst-libs/gst/gl/gstglwindow_x11.h b/gst-libs/gst/gl/gstglwindow_x11.h new file mode 100644 index 0000000000..755629e36d --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_x11.h @@ -0,0 +1,105 @@ +/* + * 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_WINDOW_X11_H__ +#define __GST_GL_WINDOW_X11_H__ + +#include +#include + +#include "gstglwindow.h" + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW_X11 (gst_gl_window_x11_get_type()) +#define GST_GL_WINDOW_X11(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_X11, GstGLWindowX11)) +#define GST_GL_WINDOW_X11_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_X11, GstGLWindowX11Class)) +#define GST_GL_IS_WINDOW_X11(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_X11)) +#define GST_GL_IS_WINDOW_X11_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_X11)) +#define GST_GL_WINDOW_X11_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_X11, GstGLWindowX11Class)) + +typedef struct _GstGLWindowX11 GstGLWindowX11; +typedef struct _GstGLWindowX11Private GstGLWindowX11Private; +typedef struct _GstGLWindowX11Class GstGLWindowX11Class; + +struct _GstGLWindowX11 { + /*< private >*/ + GstGLWindow parent; + + GCond cond_send_message; + gboolean running; + gboolean visible; + gboolean allow_extra_expose_events; + + /* opengl context */ + gchar *display_name; + Display *device; + Screen *screen; + gint screen_num; + Visual *visual; + Window root; + gulong white; + gulong black; + gint depth; + gint device_width; + gint device_height; + gint connection; + XVisualInfo *visual_info; + Window parent_win; + + /* We use a specific connection to send events */ + Display *disp_send; + + /* X window */ + Window internal_win_id; + + /*< private >*/ + GstGLWindowX11Private *priv; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLWindowX11Class { + /*< private >*/ + GstGLWindowClass parent_class; + + gboolean (*choose_visual) (GstGLWindowX11 *window); + gboolean (*create_context) (GstGLWindowX11 *window, GstGLRendererAPI render_api, + guintptr external_gl_context); + void (*swap_buffers) (GstGLWindowX11 *window); + gboolean (*activate) (GstGLWindowX11 *window, gboolean activate); + void (*destroy_context) (GstGLWindowX11 *window); + guintptr (*get_gl_context) (GstGLWindowX11 *window); + + /*< private >*/ + gpointer _reserved[GST_PADDING_LARGE]; +}; + +GType gst_gl_window_x11_get_type (void); + +GstGLWindowX11 * gst_gl_window_x11_new (GstGLRendererAPI render_api, + guintptr external_gl_context); +gboolean gst_gl_window_x11_open_device (GstGLWindowX11 *window_x11, + GstGLRendererAPI render_api, + guintptr external_gl_context); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_X11_H__ */ diff --git a/gst-libs/gst/gl/gstglwindow_x11ES2.c b/gst-libs/gst/gl/gstglwindow_x11ES2.c deleted file mode 100644 index 2b0b1c846b..0000000000 --- a/gst-libs/gst/gl/gstglwindow_x11ES2.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Julien Isorce - * - * 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. - */ - -#define GLIB_DISABLE_DEPRECATION_WARNINGS - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstglwindow.h" - -#include - -#include -#include - -#define GST_GL_WINDOW_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate)) - - -/* A gl window is created and deleted in a thread dedicated to opengl calls - The name contains "window" because an opengl context is used in cooperation - with a window */ - -const gchar *EGLErrorString (); - -enum -{ - ARG_0, - ARG_DISPLAY -}; - -struct _GstGLWindowPrivate -{ - /* X is not thread safe */ - GMutex *x_lock; - GCond *cond_send_message; - gboolean running; - gboolean visible; - gboolean allow_extra_expose_events; - - /* X context */ - gchar *display_name; - Display *device; - gint screen_num; - Window root; - gint depth; - gint device_width; - gint device_height; - gint connection; - XVisualInfo *visual_info; - Window parent; - Window internal_win_id; - - /* We use a specific connection to send events */ - Display *disp_send; - - /* EGL */ - EGLContext gl_context; - EGLDisplay gl_display; - EGLSurface gl_surface; - - /* frozen callbacks */ - GstGLWindowCB draw_cb; - gpointer draw_data; - GstGLWindowCB2 resize_cb; - gpointer resize_data; - GstGLWindowCB close_cb; - gpointer close_data; -}; - -G_DEFINE_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT); - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "GstGLWindow" - -gboolean _gst_gl_window_debug = FALSE; - -void -gst_gl_window_init_platform () -{ -} - -/* Must be called in the gl thread */ -static void -gst_gl_window_finalize (GObject * object) -{ - GstGLWindow *window = GST_GL_WINDOW (object); - GstGLWindowPrivate *priv = window->priv; - XEvent event; - Bool ret = TRUE; - - g_mutex_lock (priv->x_lock); - - g_debug ("about to finalize gl window\n"); - - priv->parent = 0; - - if (priv->device) - XUnmapWindow (priv->device, priv->internal_win_id); - - if (priv->gl_context) { - ret = - eglMakeCurrent (priv->device, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (!ret) - g_debug ("failed to release opengl context\n"); - - eglDestroyContext (priv->device, priv->gl_context); - } - - if (priv->device) - eglTerminate (priv->device); - - XFree (priv->visual_info); - - XReparentWindow (priv->device, priv->internal_win_id, priv->root, 0, 0); - - XDestroyWindow (priv->device, priv->internal_win_id); - - XSync (priv->device, FALSE); - - while (XPending (priv->device)) - XNextEvent (priv->device, &event); - - XSetCloseDownMode (priv->device, DestroyAll); - - /*XAddToSaveSet (display, w) - Display *display; - Window w; */ - - //FIXME: it seems it causes destroy all created windows, even by other display connection: - //This is case in: gst-launch-0.10 videotestsrc ! tee name=t t. ! queue ! glimagesink t. ! queue ! glimagesink - //When the first window is closed and so its display is closed by the following line, then the other Window managed by the - //other glimagesink, is not useable and so each opengl call causes a segmentation fault. - //Maybe the solution is to use: XAddToSaveSet - //The following line is commented to avoid the disagreement explained before. - //XCloseDisplay (priv->device); - - g_debug ("display receiver closed\n"); - - XCloseDisplay (priv->disp_send); - - g_debug ("display sender closed\n"); - - if (priv->cond_send_message) { - g_cond_free (priv->cond_send_message); - priv->cond_send_message = NULL; - } - - g_mutex_unlock (priv->x_lock); - - if (priv->x_lock) { - g_mutex_free (priv->x_lock); - priv->x_lock = NULL; - } - - G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object); -} - -static void -gst_gl_window_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstGLWindow *window; - GstGLWindowPrivate *priv; - - g_return_if_fail (GST_GL_IS_WINDOW (object)); - - window = GST_GL_WINDOW (object); - - priv = window->priv; - - switch (prop_id) { - case ARG_DISPLAY: - priv->display_name = g_strdup (g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gl_window_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstGLWindow *window; - GstGLWindowPrivate *priv; - - g_return_if_fail (GST_GL_IS_WINDOW (object)); - - window = GST_GL_WINDOW (object); - - priv = window->priv; - - switch (prop_id) { - case ARG_DISPLAY: - g_value_set_string (value, priv->display_name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gl_window_log_handler (const gchar * domain, GLogLevelFlags flags, - const gchar * message, gpointer user_data) -{ - if (_gst_gl_window_debug) { - g_log_default_handler (domain, flags, message, user_data); - } -} - -static void -gst_gl_window_class_init (GstGLWindowClass * klass) -{ - GObjectClass *obj_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GstGLWindowPrivate)); - - obj_class->finalize = gst_gl_window_finalize; - obj_class->set_property = gst_gl_window_set_property; - obj_class->get_property = gst_gl_window_get_property; - - g_object_class_install_property (obj_class, ARG_DISPLAY, - g_param_spec_string ("display", "Display", "X Display name", NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -gst_gl_window_init (GstGLWindow * window) -{ - GstGLWindowPrivate *priv = NULL; - window->priv = GST_GL_WINDOW_GET_PRIVATE (window); - priv = window->priv; - - if (g_getenv ("GST_GL_WINDOW_DEBUG") != NULL) - _gst_gl_window_debug = TRUE; - - g_log_set_handler ("GstGLWindow", G_LOG_LEVEL_DEBUG, - gst_gl_window_log_handler, NULL); - - priv->x_lock = NULL; - priv->cond_send_message = NULL; - priv->running = FALSE; - priv->visible = FALSE; - priv->allow_extra_expose_events = FALSE; - - /* X context */ - priv->display_name = NULL; - priv->device = NULL; - priv->screen_num = 0; - priv->root = 0; - priv->depth = 0; - priv->device_width = 0; - priv->device_height = 0; - priv->connection = 0; - priv->visual_info = NULL; - priv->parent = 0; - priv->internal_win_id = 0; - - /* We use a specific connection to send events */ - priv->disp_send = NULL; - - /* EGL */ - priv->gl_context = EGL_NO_CONTEXT; - priv->gl_display = 0; - priv->gl_surface = EGL_NO_SURFACE; - - /* frozen callbacks */ - priv->draw_cb = NULL; - priv->draw_data = NULL; - priv->resize_cb = NULL; - priv->resize_data = NULL; - priv->close_cb = NULL; - priv->close_data = NULL; -} - -/* Must be called in the gl thread */ -GstGLWindow * -gst_gl_window_new (guintptr external_gl_context) -{ - GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL); - GstGLWindowPrivate *priv = window->priv; - - EGLint config_attrib[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_DEPTH_SIZE, 16, - EGL_NONE - }; - - EGLint context_attrib[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - - EGLint majorVersion; - EGLint minorVersion; - EGLint numConfigs; - EGLConfig config; - - XSetWindowAttributes win_attr; - XTextProperty text_property; - XWMHints wm_hints; - unsigned long mask; - const gchar *title = "OpenGL renderer"; - Atom wm_atoms[3]; - - static gint x = 0; - static gint y = 0; - - setlocale (LC_NUMERIC, "C"); - - priv->x_lock = g_mutex_new (); - priv->cond_send_message = g_cond_new (); - priv->running = TRUE; - priv->visible = FALSE; - priv->parent = 0; - priv->allow_extra_expose_events = TRUE; - - g_mutex_lock (priv->x_lock); - - priv->device = XOpenDisplay (priv->display_name); - - XSynchronize (priv->device, FALSE); - - g_debug ("gl device id: %ld\n", (gulong) priv->device); - - priv->disp_send = XOpenDisplay (priv->display_name); - - XSynchronize (priv->disp_send, FALSE); - - g_debug ("gl display sender: %ld\n", (gulong) priv->disp_send); - - priv->screen_num = DefaultScreen (priv->device); - priv->root = RootWindow (priv->device, priv->screen_num); - priv->depth = DefaultDepth (priv->device, priv->screen_num); - - g_debug ("gl root id: %lud\n", (gulong) priv->root); - - priv->device_width = DisplayWidth (priv->device, priv->screen_num); - priv->device_height = DisplayHeight (priv->device, priv->screen_num); - - priv->visual_info = g_new0 (XVisualInfo, 1); - XMatchVisualInfo (priv->device, priv->screen_num, priv->depth, TrueColor, - priv->visual_info); - - win_attr.event_mask = - StructureNotifyMask | ExposureMask | VisibilityChangeMask; - win_attr.do_not_propagate_mask = NoEventMask; - - win_attr.background_pixmap = None; - win_attr.background_pixel = 0; - win_attr.border_pixel = 0; - - win_attr.colormap = - XCreateColormap (priv->device, priv->root, priv->visual_info->visual, - AllocNone); - - mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; - - x += 20; - y += 20; - - priv->internal_win_id = XCreateWindow (priv->device, priv->root, x, y, - 1, 1, 0, priv->visual_info->depth, InputOutput, - priv->visual_info->visual, mask, &win_attr); - - if (!priv->internal_win_id) { - g_debug ("XCreateWindow failed\n"); - goto failure; - } - - XSync (priv->device, FALSE); - - XSetWindowBackgroundPixmap (priv->device, priv->internal_win_id, None); - - g_debug ("gl window id: %lud\n", (gulong) priv->internal_win_id); - - g_debug ("gl window props: x:%d y:%d\n", x, y); - - wm_atoms[0] = XInternAtom (priv->device, "WM_DELETE_WINDOW", True); - if (wm_atoms[0] == None) - g_debug ("Cannot create WM_DELETE_WINDOW\n"); - - wm_atoms[1] = XInternAtom (priv->device, "WM_GL_WINDOW", False); - if (wm_atoms[1] == None) - g_debug ("Cannot create WM_GL_WINDOW\n"); - - wm_atoms[2] = XInternAtom (priv->device, "WM_QUIT_LOOP", False); - if (wm_atoms[2] == None) - g_debug ("Cannot create WM_QUIT_LOOP\n"); - - XSetWMProtocols (priv->device, priv->internal_win_id, wm_atoms, 2); - - wm_hints.flags = StateHint; - wm_hints.initial_state = NormalState; - wm_hints.input = False; - - XStringListToTextProperty ((char **) &title, 1, &text_property); - - XSetWMProperties (priv->device, priv->internal_win_id, &text_property, - &text_property, 0, 0, NULL, &wm_hints, NULL); - - XFree (text_property.value); - - priv->gl_display = eglGetDisplay ((EGLNativeDisplayType) priv->device); - - if (eglInitialize (priv->gl_display, &majorVersion, &minorVersion)) - g_debug ("egl initialized: %d.%d\n", majorVersion, minorVersion); - else { - g_debug ("failed to initialize egl %ld, %s\n", (gulong) priv->gl_display, - EGLErrorString ()); - goto failure; - } - - if (eglChooseConfig (priv->gl_display, config_attrib, &config, 1, - &numConfigs)) - g_debug ("config set: %ld, %ld\n", (gulong) config, (gulong) numConfigs); - else { - g_debug ("failed to set config %ld, %s\n", (gulong) priv->gl_display, - EGLErrorString ()); - goto failure; - } - - priv->gl_surface = - eglCreateWindowSurface (priv->gl_display, config, - (EGLNativeWindowType) priv->internal_win_id, NULL); - if (priv->gl_surface != EGL_NO_SURFACE) - g_debug ("surface created: %ld\n", (gulong) priv->gl_surface); - else { - g_debug ("failed to create surface %ld, %ld, %ld, %s\n", - (gulong) priv->gl_display, (gulong) priv->gl_surface, - (gulong) priv->gl_display, EGLErrorString ()); - goto failure; - } - - g_debug ("about to create gl context\n"); - - priv->gl_context = - eglCreateContext (priv->gl_display, config, - (EGLContext) (guint) external_gl_context, context_attrib); - - if (priv->gl_context != EGL_NO_CONTEXT) - g_debug ("gl context created: %ld\n", (gulong) priv->gl_context); - else { - g_debug ("failed to create glcontext %ld, %ld, %s\n", - (gulong) priv->gl_context, (gulong) priv->gl_display, - EGLErrorString ()); - goto failure; - } - - if (!eglMakeCurrent (priv->gl_display, priv->gl_surface, priv->gl_surface, - priv->gl_context)) { - g_debug ("failed to make opengl context current %ld, %s\n", - (gulong) priv->gl_display, EGLErrorString ()); - goto failure; - } - - g_mutex_unlock (priv->x_lock); - - return window; - -failure: - g_mutex_unlock (priv->x_lock); - g_object_unref (G_OBJECT (window)); - return NULL; -} - -GQuark -gst_gl_window_error_quark (void) -{ - return g_quark_from_static_string ("gst-gl-window-error"); -} - -guintptr -gst_gl_window_get_internal_gl_context (GstGLWindow * window) -{ - GstGLWindowPrivate *priv = window->priv; - return (guintptr) priv->gl_context; -} - -void -callback_activate_gl_context (GstGLWindowPrivate * priv) -{ - if (!eglMakeCurrent (priv->gl_display, priv->gl_surface, priv->gl_surface, - priv->gl_context)) - g_debug ("failed to activate opengl context %lud\n", - (gulong) priv->gl_context); -} - -void -callback_inactivate_gl_context (GstGLWindowPrivate * priv) -{ - if (!eglMakeCurrent (priv->device, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT)) - g_debug ("failed to inactivate opengl context %lud\n", - (gulong) priv->gl_context); -} - -void -gst_gl_window_activate_gl_context (GstGLWindow * window, gboolean activate) -{ - GstGLWindowPrivate *priv = window->priv; - if (activate) - gst_gl_window_send_message (window, - GST_GL_WINDOW_CB (callback_activate_gl_context), priv); - else - gst_gl_window_send_message (window, - GST_GL_WINDOW_CB (callback_inactivate_gl_context), priv); -} - -/* Not called by the gl thread */ -void -gst_gl_window_set_external_window_id (GstGLWindow * window, guintptr id) -{ - if (window) { - GstGLWindowPrivate *priv = window->priv; - XWindowAttributes attr; - - g_mutex_lock (priv->x_lock); - - priv->parent = (Window) id; - - g_debug ("set parent window id: %lud\n", (gulong) id); - - XGetWindowAttributes (priv->disp_send, priv->parent, &attr); - - XResizeWindow (priv->disp_send, priv->internal_win_id, attr.width, - attr.height); - - XReparentWindow (priv->disp_send, priv->internal_win_id, priv->parent, - 0, 0); - - XSync (priv->disp_send, FALSE); - - g_mutex_unlock (priv->x_lock); - } -} - -void -gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->draw_cb = callback; - priv->draw_data = data; - - g_mutex_unlock (priv->x_lock); -} - -void -gst_gl_window_set_resize_callback (GstGLWindow * window, - GstGLWindowCB2 callback, gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->resize_cb = callback; - priv->resize_data = data; - - g_mutex_unlock (priv->x_lock); -} - -void -gst_gl_window_set_close_callback (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - priv->close_cb = callback; - priv->close_data = data; - - g_mutex_unlock (priv->x_lock); -} - -/* Called in the gl thread */ -void -gst_gl_window_draw_unlocked (GstGLWindow * window, gint width, gint height) -{ - GstGLWindowPrivate *priv = window->priv; - - if (priv->running && priv->allow_extra_expose_events) { - XEvent event; - XWindowAttributes attr; - - XGetWindowAttributes (priv->device, priv->internal_win_id, &attr); - - event.xexpose.type = Expose; - event.xexpose.send_event = TRUE; - event.xexpose.display = priv->device; - event.xexpose.window = priv->internal_win_id; - event.xexpose.x = attr.x; - event.xexpose.y = attr.y; - event.xexpose.width = attr.width; - event.xexpose.height = attr.height; - event.xexpose.count = 0; - - XSendEvent (priv->device, priv->internal_win_id, FALSE, ExposureMask, - &event); - XSync (priv->disp_send, FALSE); - } -} - -/* Not called by the gl thread */ -void -gst_gl_window_draw (GstGLWindow * window, gint width, gint height) -{ - if (window) { - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - if (priv->running) { - XEvent event; - XWindowAttributes attr; - - XGetWindowAttributes (priv->disp_send, priv->internal_win_id, &attr); - - if (!priv->visible) { - - if (!priv->parent) { - attr.width = width; - attr.height = height; - XResizeWindow (priv->disp_send, priv->internal_win_id, - attr.width, attr.height); - XSync (priv->disp_send, FALSE); - } - - XMapWindow (priv->disp_send, priv->internal_win_id); - priv->visible = TRUE; - } - - if (priv->parent) { - XWindowAttributes attr_parent; - XGetWindowAttributes (priv->disp_send, priv->parent, &attr_parent); - - if (attr.width != attr_parent.width || - attr.height != attr_parent.height) { - XMoveResizeWindow (priv->disp_send, priv->internal_win_id, - 0, 0, attr_parent.width, attr_parent.height); - XSync (priv->disp_send, FALSE); - - attr.width = attr_parent.width; - attr.height = attr_parent.height; - - g_debug ("parent resize: %d, %d\n", - attr_parent.width, attr_parent.height); - } - } - - event.xexpose.type = Expose; - event.xexpose.send_event = TRUE; - event.xexpose.display = priv->disp_send; - event.xexpose.window = priv->internal_win_id; - event.xexpose.x = attr.x; - event.xexpose.y = attr.y; - event.xexpose.width = attr.width; - event.xexpose.height = attr.height; - event.xexpose.count = 0; - - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, ExposureMask, - &event); - XSync (priv->disp_send, FALSE); - } - - g_mutex_unlock (priv->x_lock); - } -} - -/* Called in the gl thread */ -void -gst_gl_window_run_loop (GstGLWindow * window) -{ - GstGLWindowPrivate *priv = window->priv; - - g_debug ("begin loop\n"); - - g_mutex_lock (priv->x_lock); - - while (priv->running) { - XEvent event; - XEvent pending_event; - - g_mutex_unlock (priv->x_lock); - - /* XSendEvent (which are called in other threads) are done from another display structure */ - XNextEvent (priv->device, &event); - - g_mutex_lock (priv->x_lock); - - // use in generic/cube and other related uses - priv->allow_extra_expose_events = XPending (priv->device) <= 2; - - switch (event.type) { - case ClientMessage: - { - - Atom wm_delete = XInternAtom (priv->device, "WM_DELETE_WINDOW", True); - Atom wm_gl = XInternAtom (priv->device, "WM_GL_WINDOW", True); - Atom wm_quit_loop = XInternAtom (priv->device, "WM_QUIT_LOOP", True); - - if (wm_delete == None) - g_debug ("Cannot create WM_DELETE_WINDOW\n"); - if (wm_gl == None) - g_debug ("Cannot create WM_GL_WINDOW\n"); - if (wm_quit_loop == None) - g_debug ("Cannot create WM_QUIT_LOOP\n"); - - /* Message sent with gst_gl_window_send_message */ - if (wm_gl != None && event.xclient.message_type == wm_gl) { - if (priv->running) { -#if SIZEOF_VOID_P == 8 - GstGLWindowCB custom_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); - gpointer custom_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); -#else - GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0]; - gpointer custom_data = (gpointer) event.xclient.data.l[1]; -#endif - - if (!custom_cb || !custom_data) - g_debug ("custom cb not initialized\n"); - - custom_cb (custom_data); - } - - g_cond_signal (priv->cond_send_message); - } - - /* User clicked on the cross */ - else if (wm_delete != None - && (Atom) event.xclient.data.l[0] == wm_delete) { - g_debug ("Close %lud\n", (gulong) priv->internal_win_id); - - if (priv->close_cb) - priv->close_cb (priv->close_data); - - priv->draw_cb = NULL; - priv->draw_data = NULL; - priv->resize_cb = NULL; - priv->resize_data = NULL; - priv->close_cb = NULL; - priv->close_data = NULL; - } - - /* message sent with gst_gl_window_quit_loop */ - else if (wm_quit_loop != None - && event.xclient.message_type == wm_quit_loop) { -#if SIZEOF_VOID_P == 8 - GstGLWindowCB destroy_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); - gpointer destroy_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); -#else - GstGLWindowCB destroy_cb = (GstGLWindowCB) event.xclient.data.l[0]; - gpointer destroy_data = (gpointer) event.xclient.data.l[1]; -#endif - - g_debug ("Quit loop message %lud\n", (gulong) priv->internal_win_id); - - /* exit loop */ - priv->running = FALSE; - - /* make sure last pendings send message calls are executed */ - XFlush (priv->device); - while (XCheckTypedEvent (priv->device, ClientMessage, &pending_event)) { -#if SIZEOF_VOID_P == 8 - GstGLWindowCB custom_cb = - (GstGLWindowCB) (((event.xclient.data. - l[0] & 0xffffffff) << 32) | (event.xclient.data. - l[1] & 0xffffffff)); - gpointer custom_data = - (gpointer) (((event.xclient.data. - l[2] & 0xffffffff) << 32) | (event.xclient.data. - l[3] & 0xffffffff)); -#else - GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0]; - gpointer custom_data = (gpointer) event.xclient.data.l[1]; -#endif - g_debug ("execute last pending custom x events\n"); - - if (!custom_cb || !custom_data) - g_debug ("custom cb not initialized\n"); - - custom_cb (custom_data); - - g_cond_signal (priv->cond_send_message); - } - - /* Finally we can destroy opengl ressources (texture/shaders/fbo) */ - if (!destroy_cb || !destroy_data) - g_debug ("destroy cb not correclty set\n"); - - destroy_cb (destroy_data); - - } else - g_debug ("client message not reconized \n"); - break; - } - - case CreateNotify: - case ConfigureNotify: - { - if (priv->resize_cb) - priv->resize_cb (priv->resize_data, event.xconfigure.width, - event.xconfigure.height); - break; - } - - case DestroyNotify: - g_debug ("DestroyNotify\n"); - break; - - case Expose: - if (priv->draw_cb) { - priv->draw_cb (priv->draw_data); - glFlush (); - eglSwapBuffers (priv->gl_display, priv->gl_surface); - } - break; - - case VisibilityNotify: - { - switch (event.xvisibility.state) { - case VisibilityUnobscured: - if (priv->draw_cb) - priv->draw_cb (priv->draw_data); - break; - - case VisibilityPartiallyObscured: - if (priv->draw_cb) - priv->draw_cb (priv->draw_data); - break; - - case VisibilityFullyObscured: - break; - - default: - g_debug ("unknown xvisibility event: %d\n", - event.xvisibility.state); - break; - } - break; - } - - default: - g_debug ("unknown XEvent type: %ud\n", event.type); - break; - - } // switch - - } // while running - - g_mutex_unlock (priv->x_lock); - - g_debug ("end loop\n"); -} - -/* Not called by the gl thread */ -void -gst_gl_window_quit_loop (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - if (window) { - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - if (priv->running) { - XEvent event; - - event.xclient.type = ClientMessage; - event.xclient.send_event = TRUE; - event.xclient.display = priv->disp_send; - event.xclient.window = priv->internal_win_id; - event.xclient.message_type = - XInternAtom (priv->disp_send, "WM_QUIT_LOOP", True);; - event.xclient.format = 32; -#if SIZEOF_VOID_P == 8 - event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; - event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; - event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; - event.xclient.data.l[3] = (((long) data)) & 0xffffffff; -#else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; -#endif - - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, NoEventMask, - &event); - XSync (priv->disp_send, FALSE); - } - - g_mutex_unlock (priv->x_lock); - } -} - -/* Not called by the gl thread */ -void -gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback, - gpointer data) -{ - if (window) { - GstGLWindowPrivate *priv = window->priv; - - g_mutex_lock (priv->x_lock); - - if (priv->running) { - XEvent event; - - event.xclient.type = ClientMessage; - event.xclient.send_event = TRUE; - event.xclient.display = priv->disp_send; - event.xclient.window = priv->internal_win_id; - event.xclient.message_type = - XInternAtom (priv->disp_send, "WM_GL_WINDOW", True); - event.xclient.format = 32; -#if SIZEOF_VOID_P == 8 - event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff; - event.xclient.data.l[1] = (((long) callback)) & 0xffffffff; - event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff; - event.xclient.data.l[3] = (((long) data)) & 0xffffffff; -#else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; -#endif - - XSendEvent (priv->disp_send, priv->internal_win_id, FALSE, NoEventMask, - &event); - XSync (priv->disp_send, FALSE); - - /* block until opengl calls have been executed in the gl thread */ - g_cond_wait (priv->cond_send_message, priv->x_lock); - } - - g_mutex_unlock (priv->x_lock); - } -} - -const gchar * -EGLErrorString () -{ - EGLint nErr = eglGetError (); - switch (nErr) { - case EGL_SUCCESS: - return "EGL_SUCCESS"; - case EGL_BAD_DISPLAY: - return "EGL_BAD_DISPLAY"; - case EGL_NOT_INITIALIZED: - return "EGL_NOT_INITIALIZED"; - case EGL_BAD_ACCESS: - return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: - return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: - return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONFIG: - return "EGL_BAD_CONFIG"; - case EGL_BAD_CONTEXT: - return "EGL_BAD_CONTEXT"; - case EGL_BAD_CURRENT_SURFACE: - return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_MATCH: - return "EGL_BAD_MATCH"; - case EGL_BAD_NATIVE_PIXMAP: - return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: - return "EGL_BAD_NATIVE_WINDOW"; - case EGL_BAD_PARAMETER: - return "EGL_BAD_PARAMETER"; - case EGL_BAD_SURFACE: - return "EGL_BAD_SURFACE"; - default: - return "unknown"; - } -} diff --git a/gst-libs/gst/gl/gstglwindow_x11_egl.c b/gst-libs/gst/gl/gstglwindow_x11_egl.c new file mode 100644 index 0000000000..7513acc55c --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_x11_egl.c @@ -0,0 +1,271 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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. + */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstglwindow_x11_egl.h" + +const gchar *EGLErrorString (); + +#define GST_CAT_DEFAULT gst_gl_window_x11_egl_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow"); +#define gst_gl_window_x11_egl_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGLWindowX11EGL, gst_gl_window_x11_egl, + GST_GL_TYPE_WINDOW_X11, DEBUG_INIT); + +static guintptr gst_gl_window_x11_egl_get_gl_context (GstGLWindowX11 * + window_x11); +static void gst_gl_window_x11_egl_swap_buffers (GstGLWindowX11 * window_x11); +static gboolean gst_gl_window_x11_egl_activate (GstGLWindowX11 * window_x11, + gboolean activate); +static gboolean gst_gl_window_x11_egl_create_context (GstGLWindowX11 * + window_x11, GstGLRendererAPI render_api, guintptr external_gl_context); +static void gst_gl_window_x11_egl_destroy_context (GstGLWindowX11 * window_x11); +static gboolean gst_gl_window_x11_egl_choose_visual (GstGLWindowX11 * + window_x11); +static GstGLPlatform gst_gl_window_x11_egl_get_platform (GstGLWindow * window); + +static void +gst_gl_window_x11_egl_class_init (GstGLWindowX11EGLClass * klass) +{ + GstGLWindowClass *window_class = (GstGLWindowClass *) klass; + GstGLWindowX11Class *window_x11_class = (GstGLWindowX11Class *) klass; + + window_class->get_platform = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_get_platform); + + window_x11_class->get_gl_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_get_gl_context); + window_x11_class->activate = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_activate); + window_x11_class->create_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_create_context); + window_x11_class->destroy_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_destroy_context); + window_x11_class->choose_visual = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_choose_visual); + window_x11_class->swap_buffers = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_egl_swap_buffers); +} + +static void +gst_gl_window_x11_egl_init (GstGLWindowX11EGL * window) +{ +} + +/* Must be called in the gl thread */ +GstGLWindowX11EGL * +gst_gl_window_x11_egl_new (GstGLRendererAPI render_api, + guintptr external_gl_context) +{ + GstGLWindowX11EGL *window = g_object_new (GST_GL_TYPE_WINDOW_X11_EGL, NULL); + + gst_gl_window_x11_open_device (GST_GL_WINDOW_X11 (window), render_api, + external_gl_context); + + return window; +} + +static GstGLPlatform +gst_gl_window_x11_egl_get_platform (GstGLWindow * window) +{ + return GST_GL_PLATFORM_EGL; +} + +static gboolean +gst_gl_window_x11_egl_choose_visual (GstGLWindowX11 * window_x11) +{ + gint ret; + + window_x11->visual_info = g_new0 (XVisualInfo, 1); + ret = XMatchVisualInfo (window_x11->device, window_x11->screen_num, + window_x11->depth, TrueColor, window_x11->visual_info); + + return ret != 0; +} + +static gboolean +gst_gl_window_x11_egl_create_context (GstGLWindowX11 * window_x11, + GstGLRendererAPI render_api, guintptr external_gl_context) +{ + GstGLWindowX11EGL *window_egl; + + EGLint config_attrib[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_DEPTH_SIZE, 16, + EGL_NONE + }; + + EGLint context_attrib[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + EGLint majorVersion; + EGLint minorVersion; + EGLint numConfigs; + EGLConfig config; + + window_egl = GST_GL_WINDOW_X11_EGL (window_x11); + + window_egl->egl_display = + eglGetDisplay ((EGLNativeDisplayType) window_x11->device); + + if (eglInitialize (window_egl->egl_display, &majorVersion, &minorVersion)) + g_debug ("egl initialized: %d.%d\n", majorVersion, minorVersion); + else { + g_debug ("failed to initialize egl %ld, %s\n", + (gulong) window_egl->egl_display, EGLErrorString ()); + goto failure; + } + + if (eglChooseConfig (window_egl->egl_display, config_attrib, &config, 1, + &numConfigs)) + g_debug ("config set: %ld, %ld\n", (gulong) config, (gulong) numConfigs); + else { + g_debug ("failed to set config %ld, %s\n", (gulong) window_egl->egl_display, + EGLErrorString ()); + goto failure; + } + + window_egl->egl_surface = + eglCreateWindowSurface (window_egl->egl_display, config, + (EGLNativeWindowType) window_x11->internal_win_id, NULL); + if (window_egl->egl_surface != EGL_NO_SURFACE) + g_debug ("surface created: %ld\n", (gulong) window_egl->egl_surface); + else { + g_debug ("failed to create surface %ld, %ld, %ld, %s\n", + (gulong) window_egl->egl_display, (gulong) window_egl->egl_surface, + (gulong) window_egl->egl_display, EGLErrorString ()); + goto failure; + } + + g_debug ("about to create gl context\n"); + + window_egl->egl_context = + eglCreateContext (window_egl->egl_display, config, + (EGLContext) external_gl_context, context_attrib); + + if (window_egl->egl_context != EGL_NO_CONTEXT) + g_debug ("gl context created: %ld\n", (gulong) window_egl->egl_context); + else { + g_debug ("failed to create glcontext %ld, %ld, %s\n", + (gulong) window_egl->egl_context, (gulong) window_egl->egl_display, + EGLErrorString ()); + goto failure; + } + + return TRUE; + +failure: + return FALSE; +} + +static void +gst_gl_window_x11_egl_destroy_context (GstGLWindowX11 * window_x11) +{ + GstGLWindowX11EGL *window_egl; + + window_egl = GST_GL_WINDOW_X11_EGL (window_x11); + + if (window_egl->egl_context) + eglDestroyContext (window_x11->device, window_egl->egl_context); + + if (window_x11->device) + eglTerminate (window_x11->device); +} + +static gboolean +gst_gl_window_x11_egl_activate (GstGLWindowX11 * window_x11, gboolean activate) +{ + gboolean result; + GstGLWindowX11EGL *window_egl; + + window_egl = GST_GL_WINDOW_X11_EGL (window_x11); + + if (activate) + result = eglMakeCurrent (window_egl->egl_display, window_egl->egl_surface, + window_egl->egl_surface, window_egl->egl_context); + else + result = eglMakeCurrent (window_egl->egl_display, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT); + + return result; +} + +static guintptr +gst_gl_window_x11_egl_get_gl_context (GstGLWindowX11 * window_x11) +{ + return (guintptr) GST_GL_WINDOW_X11_EGL (window_x11)->egl_context; +} + +static void +gst_gl_window_x11_egl_swap_buffers (GstGLWindowX11 * window_x11) +{ + GstGLWindowX11EGL *window_egl = GST_GL_WINDOW_X11_EGL (window_x11); + + eglSwapBuffers (window_egl->egl_display, window_egl->egl_surface); +} + +const gchar * +EGLErrorString () +{ + EGLint nErr = eglGetError (); + switch (nErr) { + case EGL_SUCCESS: + return "EGL_SUCCESS"; + case EGL_BAD_DISPLAY: + return "EGL_BAD_DISPLAY"; + case EGL_NOT_INITIALIZED: + return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: + return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: + return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: + return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONFIG: + return "EGL_BAD_CONFIG"; + case EGL_BAD_CONTEXT: + return "EGL_BAD_CONTEXT"; + case EGL_BAD_CURRENT_SURFACE: + return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_MATCH: + return "EGL_BAD_MATCH"; + case EGL_BAD_NATIVE_PIXMAP: + return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: + return "EGL_BAD_NATIVE_WINDOW"; + case EGL_BAD_PARAMETER: + return "EGL_BAD_PARAMETER"; + case EGL_BAD_SURFACE: + return "EGL_BAD_SURFACE"; + default: + return "unknown"; + } +} diff --git a/gst-libs/gst/gl/gstglwindow_x11_egl.h b/gst-libs/gst/gl/gstglwindow_x11_egl.h new file mode 100644 index 0000000000..c1ce40bf71 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_x11_egl.h @@ -0,0 +1,66 @@ +/* + * 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_WINDOW_X11_EGL_H__ +#define __GST_GL_WINDOW_X11_EGL_H__ + +#include + +#include "gstglwindow_x11.h" + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW_X11_EGL (gst_gl_window_x11_egl_get_type()) +#define GST_GL_WINDOW_X11_EGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_X11_EGL, GstGLWindowX11EGL)) +#define GST_GL_WINDOW_X11_EGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_X11_EGL, GstGLWindowX11EGLClass)) +#define GST_GL_IS_WINDOW_X11_EGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_X11_EGL)) +#define GST_GL_IS_WINDOW_X11_EGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_X11_EGL)) +#define GST_GL_WINDOW_X11_EGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_X11_EGL, GstGLWindowX11EGL_Class)) + +typedef struct _GstGLWindowX11EGL GstGLWindowX11EGL; +typedef struct _GstGLWindowX11EGLClass GstGLWindowX11EGLClass; + +struct _GstGLWindowX11EGL { + /*< private >*/ + GstGLWindowX11 parent; + + EGLContext egl_context; + EGLDisplay egl_display; + EGLSurface egl_surface; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLWindowX11EGLClass { + /*< private >*/ + GstGLWindowX11Class parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; +}; + +GType gst_gl_window_x11_egl_get_type (void); + +GstGLWindowX11EGL * gst_gl_window_x11_egl_new (GstGLRendererAPI render_api, + guintptr external_gl_context); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_X11_H__ */ diff --git a/gst-libs/gst/gl/gstglwindow_x11_glx.c b/gst-libs/gst/gl/gstglwindow_x11_glx.c new file mode 100644 index 0000000000..25292d7359 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_x11_glx.c @@ -0,0 +1,183 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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. + */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstglwindow_x11_glx.h" + +#define GST_CAT_DEFAULT gst_gl_window_x11_glx_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow"); +#define gst_gl_window_x11_glx_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstGLWindowX11GLX, gst_gl_window_x11_glx, + GST_GL_TYPE_WINDOW_X11, DEBUG_INIT); + +static guintptr gst_gl_window_x11_glx_get_gl_context (GstGLWindowX11 * + window_x11); +static void gst_gl_window_x11_glx_swap_buffers (GstGLWindowX11 * window_x11); +static gboolean gst_gl_window_x11_glx_activate (GstGLWindowX11 * window_x11, + gboolean activate); +static gboolean gst_gl_window_x11_glx_create_context (GstGLWindowX11 * + window_x11, GstGLRendererAPI render_api, guintptr external_gl_context); +static void gst_gl_window_x11_glx_destroy_context (GstGLWindowX11 * window_x11); +static gboolean gst_gl_window_x11_glx_choose_visual (GstGLWindowX11 * + window_x11); + +static void +gst_gl_window_x11_glx_class_init (GstGLWindowX11GLXClass * klass) +{ + GstGLWindowX11Class *window_x11_class = (GstGLWindowX11Class *) klass; + + window_x11_class->get_gl_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_get_gl_context); + window_x11_class->activate = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_activate); + window_x11_class->create_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_create_context); + window_x11_class->destroy_context = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_destroy_context); + window_x11_class->choose_visual = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_choose_visual); + window_x11_class->swap_buffers = + GST_DEBUG_FUNCPTR (gst_gl_window_x11_glx_swap_buffers); +} + +static void +gst_gl_window_x11_glx_init (GstGLWindowX11GLX * window) +{ +} + +/* Must be called in the gl thread */ +GstGLWindowX11GLX * +gst_gl_window_x11_glx_new (GstGLRendererAPI render_api, + guintptr external_gl_context) +{ + GstGLWindowX11GLX *window = g_object_new (GST_GL_TYPE_WINDOW_X11_GLX, NULL); + + gst_gl_window_x11_open_device (GST_GL_WINDOW_X11 (window), render_api, + external_gl_context); + + return window; +} + +static gboolean +gst_gl_window_x11_glx_create_context (GstGLWindowX11 * window_x11, + GstGLRendererAPI render_api, guintptr external_gl_context) +{ + GstGLWindowX11GLX *window_glx; + + window_glx = GST_GL_WINDOW_X11_GLX (window_x11); + + window_glx->glx_context = + glXCreateContext (window_x11->device, window_x11->visual_info, + (GLXContext) external_gl_context, TRUE); + + if (!window_glx->glx_context) { + GST_WARNING ("failed to create opengl context (glXCreateContext failed)"); + goto failure; + } + + GST_LOG ("gl context id: %ld", (gulong) window_glx->glx_context); + + return TRUE; + +failure: + return FALSE; +} + +static void +gst_gl_window_x11_glx_destroy_context (GstGLWindowX11 * window_x11) +{ + GstGLWindowX11GLX *window_glx; + + window_glx = GST_GL_WINDOW_X11_GLX (window_x11); + + glXDestroyContext (window_x11->device, window_glx->glx_context); + + window_glx->glx_context = 0; +} + +static gboolean +gst_gl_window_x11_glx_choose_visual (GstGLWindowX11 * window_x11) +{ + gint error_base; + gint event_base; + + gint attrib[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 16, + GLX_DOUBLEBUFFER, + None + }; + + if (!glXQueryExtension (window_x11->device, &error_base, &event_base)) { + GST_WARNING ("No GLX extension"); + goto failure; + } + + window_x11->visual_info = glXChooseVisual (window_x11->device, + window_x11->screen_num, attrib); + + if (!window_x11->visual_info) { + GST_WARNING ("glx visual is null (bad attributes)"); + goto failure; + } + + return TRUE; + +failure: + return FALSE; +} + +static void +gst_gl_window_x11_glx_swap_buffers (GstGLWindowX11 * window_x11) +{ + glXSwapBuffers (window_x11->device, window_x11->internal_win_id); +} + +static guintptr +gst_gl_window_x11_glx_get_gl_context (GstGLWindowX11 * window_x11) +{ + return (guintptr) GST_GL_WINDOW_X11_GLX (window_x11)->glx_context; +} + +static gboolean +gst_gl_window_x11_glx_activate (GstGLWindowX11 * window_x11, gboolean activate) +{ + gboolean result; + + if (activate) { + result = glXMakeCurrent (window_x11->device, window_x11->internal_win_id, + GST_GL_WINDOW_X11_GLX (window_x11)->glx_context); + } else { + result = glXMakeCurrent (window_x11->device, None, NULL); + } + + return result; +} diff --git a/gst-libs/gst/gl/gstglwindow_x11_glx.h b/gst-libs/gst/gl/gstglwindow_x11_glx.h new file mode 100644 index 0000000000..e9c065c346 --- /dev/null +++ b/gst-libs/gst/gl/gstglwindow_x11_glx.h @@ -0,0 +1,64 @@ +/* + * 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_WINDOW_X11_GLX_H__ +#define __GST_GL_WINDOW_X11_GLX_H__ + +#include + +#include "gstglwindow_x11.h" + +G_BEGIN_DECLS + +#define GST_GL_TYPE_WINDOW_X11_GLX (gst_gl_window_x11_glx_get_type()) +#define GST_GL_WINDOW_X11_GLX(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_X11_GLX, GstGLWindowX11GLX)) +#define GST_GL_WINDOW_X11_GLX_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_X11_GLX, GstGLWindowX11GLXClass)) +#define GST_GL_IS_WINDOW_X11_GLX(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_X11_GLX)) +#define GST_GL_IS_WINDOW_X11_GLX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_X11_GLX)) +#define GST_GL_WINDOW_X11_GLX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_X11_GLX, GstGLWindowX11GLX_Class)) + +typedef struct _GstGLWindowX11GLX GstGLWindowX11GLX; +typedef struct _GstGLWindowX11GLXClass GstGLWindowX11GLXClass; + +struct _GstGLWindowX11GLX { + /*< private >*/ + GstGLWindowX11 parent; + + GLXContext glx_context; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLWindowX11GLXClass { + /*< private >*/ + GstGLWindowX11Class parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; +}; + +GType gst_gl_window_x11_glx_get_type (void); + +GstGLWindowX11GLX * gst_gl_window_x11_glx_new (GstGLRendererAPI render_api, + guintptr external_gl_context); + +G_END_DECLS + +#endif /* __GST_GL_WINDOW_X11_H__ */