From: Matthew Waters Date: Tue, 2 Jul 2013 12:06:03 +0000 (+1000) Subject: [725/906] x11: use GMainContext/GMainLoop X-Git-Tag: 1.19.3~511^2~1989^2~1816 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3c2810c3d6a60ee3bcf0a805ddf87dd83921c868;p=platform%2Fupstream%2Fgstreamer.git [725/906] x11: use GMainContext/GMainLoop allows us to be reentrant https://bugzilla.gnome.org/show_bug.cgi?id=703445 --- diff --git a/gst-libs/gst/gl/x11/Makefile.am b/gst-libs/gst/gl/x11/Makefile.am index 329be2d..fa990ce 100644 --- a/gst-libs/gst/gl/x11/Makefile.am +++ b/gst-libs/gst/gl/x11/Makefile.am @@ -6,10 +6,12 @@ libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@ libgstglx11includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl/x11 libgstgl_x11_la_SOURCES = \ - gstglwindow_x11.c + gstglwindow_x11.c \ + x11_event_source.c libgstglx11include_HEADERS = \ - gstglwindow_x11.h + gstglwindow_x11.h \ + x11_event_source.h if USE_GLX libgstgl_x11_la_SOURCES += gstglwindow_x11_glx.c diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11.c b/gst-libs/gst/gl/x11/gstglwindow_x11.c index 2dde3dd..185acd8 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11.c +++ b/gst-libs/gst/gl/x11/gstglwindow_x11.c @@ -28,6 +28,7 @@ #include #include +#include "x11_event_source.h" #include "gstglwindow_x11.h" #if GST_GL_HAVE_PLATFORM_GLX @@ -157,8 +158,6 @@ static void gst_gl_window_x11_init (GstGLWindowX11 * window) { window->priv = GST_GL_WINDOW_X11_GET_PRIVATE (window); - - g_cond_init (&window->cond_send_message); } /* Must be called in the gl thread */ @@ -228,7 +227,7 @@ gst_gl_window_x11_create_context (GstGLWindow * window, setlocale (LC_NUMERIC, "C"); - gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), TRUE); + gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), FALSE); window_x11->running = TRUE; window_x11->visible = FALSE; @@ -253,7 +252,11 @@ gst_gl_window_x11_create_context (GstGLWindow * window, window_x11->device_height = DisplayHeight (window_x11->device, window_x11->screen_num); - window_x11->connection = ConnectionNumber (window_x11->device); + window_x11->x11_source = x11_event_source_new (window_x11); + window_x11->main_context = g_main_context_new (); + window_x11->loop = g_main_loop_new (window_x11->main_context, FALSE); + + g_source_attach (window_x11->x11_source, window_x11->main_context); if (!window_class->choose_format (window_x11, error)) { goto failure; @@ -286,7 +289,7 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11) XWMHints wm_hints; unsigned long mask; const gchar *title = "OpenGL renderer"; - Atom wm_atoms[3]; + Atom wm_atoms[1]; static gint x = 0; static gint y = 0; @@ -337,16 +340,8 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11) if (wm_atoms[0] == None) GST_DEBUG ("Cannot create WM_DELETE_WINDOW"); - wm_atoms[1] = XInternAtom (window_x11->device, "WM_GL_WINDOW", False); - if (wm_atoms[1] == None) - GST_DEBUG ("Cannot create WM_GL_WINDOW"); - - wm_atoms[2] = XInternAtom (window_x11->device, "WM_QUIT_LOOP", False); - if (wm_atoms[2] == None) - GST_DEBUG ("Cannot create WM_QUIT_LOOP"); - XSetWMProtocols (window_x11->device, window_x11->internal_win_id, wm_atoms, - 2); + 1); wm_hints.flags = StateHint; wm_hints.initial_state = NormalState; @@ -413,8 +408,6 @@ gst_gl_window_x11_close (GstGLWindow * window) GST_DEBUG ("display sender closed"); } - g_cond_clear (&window_x11->cond_send_message); - GST_GL_WINDOW_UNLOCK (window_x11); } @@ -577,143 +570,76 @@ gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height) } } -/* Called in the gl thread */ +typedef struct _GstGLMessage +{ + GstGLWindow *window; + GMutex lock; + GCond cond; + gboolean fired; + + GstGLWindowCB callback; + gpointer data; +} GstGLMessage; + +static gboolean +_run_message (GstGLMessage * message) +{ + g_mutex_lock (&message->lock); + + if (message->callback) + message->callback (message->data); + + message->fired = TRUE; + g_cond_signal (&message->cond); + g_mutex_unlock (&message->lock); + + return FALSE; +} + void gst_gl_window_x11_run (GstGLWindow * window) { GstGLWindowX11 *window_x11; - GstGLWindowX11Class *window_class; window_x11 = GST_GL_WINDOW_X11 (window); - window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); - GST_DEBUG ("begin loop"); + g_main_loop_run (window_x11->loop); +} - while (window_x11->running) { - XEvent event; - XEvent pending_event; +void +gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11) +{ + GstGLWindow *window; + GstGLWindowX11Class *window_class; - GST_GL_WINDOW_UNLOCK (window); + window = GST_GL_WINDOW (window_x11); + window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11); + + if (window_x11->running && XPending (window_x11->device)) { + XEvent event; /* XSendEvent (which are called in other threads) are done from another display structure */ XNextEvent (window_x11->device, &event); - GST_GL_WINDOW_LOCK (window); - // use in generic/cube and other related uses window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2; switch (event.type) { case ClientMessage: { - 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) GST_DEBUG ("Cannot create WM_DELETE_WINDOW"); - if (wm_gl == None) - GST_DEBUG ("Cannot create WM_GL_WINDOW"); - if (wm_quit_loop == None) - 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 (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)); - 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) - GST_DEBUG ("custom cb not initialized"); - - custom_cb (custom_data); - } - - 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) { + if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) { GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id); if (window->close) window->close (window->close_data); } - - /* 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 - - GST_DEBUG ("Quit loop message %lud", - (gulong) window_x11->internal_win_id); - - /* exit loop */ - window_x11->running = FALSE; - - /* make sure last pendings send message calls are executed */ - 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)); - 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 - GST_DEBUG ("execute last pending custom x events"); - - if (!custom_cb || !custom_data) - GST_DEBUG ("custom cb not initialized"); - - custom_cb (custom_data); - - g_cond_signal (&window_x11->cond_send_message); - } - - /* Finally we can destroy opengl ressources (texture/shaders/fbo) */ - if (!destroy_cb || !destroy_data) - GST_FIXME ("destroy cb not correctly set"); - - if (destroy_cb) - destroy_cb (destroy_data); - - } else - GST_DEBUG ("client message not recognized"); break; } @@ -767,7 +693,6 @@ gst_gl_window_x11_run (GstGLWindow * window) } // switch } // while running - GST_DEBUG ("end loop"); } /* Not called by the gl thread */ @@ -779,32 +704,14 @@ gst_gl_window_x11_quit (GstGLWindow * window, GstGLWindowCB callback, window_x11 = GST_GL_WINDOW_X11 (window); - GST_DEBUG ("sending quit, running:%i", window_x11->running); + if (callback) + gst_gl_window_x11_send_message (window, callback, data); - if (window_x11->running) { - XEvent event; + GST_LOG ("sending quit"); - 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; -#else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; -#endif + g_main_loop_quit (window_x11->loop); - XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE, - NoEventMask, &event); - XSync (window_x11->disp_send, FALSE); - } + GST_LOG ("quit sent"); } /* Not called by the gl thread */ @@ -817,32 +724,24 @@ gst_gl_window_x11_send_message (GstGLWindow * window, GstGLWindowCB callback, window_x11 = GST_GL_WINDOW_X11 (window); if (window_x11->running) { - XEvent event; + GstGLMessage message; - 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; -#else - event.xclient.data.l[0] = (long) callback; - event.xclient.data.l[1] = (long) data; -#endif + message.window = window; + message.callback = callback; + message.data = data; + message.fired = FALSE; + g_mutex_init (&message.lock); + g_cond_init (&message.cond); - XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE, - NoEventMask, &event); - XSync (window_x11->disp_send, FALSE); + g_main_context_invoke (window_x11->main_context, (GSourceFunc) _run_message, + &message); + + g_mutex_lock (&message.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)); + while (!message.fired) + g_cond_wait (&message.cond, &message.lock); + g_mutex_unlock (&message.lock); } } diff --git a/gst-libs/gst/gl/x11/gstglwindow_x11.h b/gst-libs/gst/gl/x11/gstglwindow_x11.h index 8271640..ea27cf1 100644 --- a/gst-libs/gst/gl/x11/gstglwindow_x11.h +++ b/gst-libs/gst/gl/x11/gstglwindow_x11.h @@ -43,8 +43,7 @@ typedef struct _GstGLWindowX11Class GstGLWindowX11Class; struct _GstGLWindowX11 { /*< private >*/ GstGLWindow parent; - - GCond cond_send_message; + gboolean running; gboolean visible; gboolean allow_extra_expose_events; @@ -71,6 +70,10 @@ struct _GstGLWindowX11 { /* X window */ Window internal_win_id; + GSource *x11_source; + GMainContext *main_context; + GMainLoop *loop; + /*< private >*/ GstGLWindowX11Private *priv; diff --git a/gst-libs/gst/gl/x11/x11_event_source.c b/gst-libs/gst/gl/x11/x11_event_source.c new file mode 100644 index 0000000..382b10a --- /dev/null +++ b/gst-libs/gst/gl/x11/x11_event_source.c @@ -0,0 +1,98 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "x11_event_source.h" + +extern void gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11); + +typedef struct _X11EventSource +{ + GSource source; + GPollFD pfd; + uint32_t mask; + GstGLWindowX11 *window; +} X11EventSource; + +static gboolean +x11_event_source_prepare (GSource * base, gint * timeout) +{ + X11EventSource *source = (X11EventSource *) base; + gboolean retval; + + *timeout = -1; + + retval = XPending (source->window->device); //clutter_events_pending (); + + return retval; +} + +static gboolean +x11_event_source_check (GSource * base) +{ + X11EventSource *source = (X11EventSource *) base; + gboolean retval; + + retval = source->pfd.revents; // || clutter_events_pending(); + + return retval; +} + +static gboolean +x11_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data) +{ + X11EventSource *source = (X11EventSource *) base; + + gst_gl_window_x11_handle_event (source->window); + + if (callback) + callback (data); + + return TRUE; +} + +static GSourceFuncs x11_event_source_funcs = { + x11_event_source_prepare, + x11_event_source_check, + x11_event_source_dispatch, + NULL +}; + +GSource * +x11_event_source_new (GstGLWindowX11 * window_x11) +{ + X11EventSource *source; + + source = (X11EventSource *) + g_source_new (&x11_event_source_funcs, sizeof (X11EventSource)); + source->window = window_x11; + source->pfd.fd = ConnectionNumber (window_x11->device); + source->pfd.events = G_IO_IN | G_IO_ERR; + g_source_add_poll (&source->source, &source->pfd); + + return &source->source; +} diff --git a/gst-libs/gst/gl/x11/x11_event_source.h b/gst-libs/gst/gl/x11/x11_event_source.h new file mode 100644 index 0000000..39f79f0 --- /dev/null +++ b/gst-libs/gst/gl/x11/x11_event_source.h @@ -0,0 +1,30 @@ +/* + * 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 __X11_EVENT_SOURCE_H__ +#define __X11_EVENT_SOURCE_H__ + +#include +#include "gstglwindow_x11.h" + +GSource * +x11_event_source_new (GstGLWindowX11 *window_x11); + +#endif /* __WAYLAND_EVENT_SOURCE_H__ */