From 57e497f9e24048f5c3dd4c966d92a680bbccc91d Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Thu, 29 Aug 2013 20:10:42 +1000 Subject: context: Reimplement GL context sharing https://bugzilla.gnome.org/show_bug.cgi?id=704806 --- gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m | 11 +++- gst-libs/gst/gl/egl/gstglcontext_egl.c | 96 ++++++++++++++++++++---------- gst-libs/gst/gl/gstglcontext.c | 14 ++--- gst-libs/gst/gl/gstglcontext.h | 7 ++- gst-libs/gst/gl/win32/gstglcontext_wgl.c | 25 +++++++- gst-libs/gst/gl/x11/gstglcontext_glx.c | 27 ++++++++- 6 files changed, 131 insertions(+), 49 deletions(-) diff --git a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m index 510b09e..e808f37 100644 --- a/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m +++ b/gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m @@ -28,7 +28,7 @@ #include "gstgl_cocoa_private.h" static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, - guintptr external_opengl_context, GError **error); + GstGLContext * other_context, GError **error); static guintptr gst_gl_context_cocoa_get_gl_context (GstGLContext * window); static gboolean gst_gl_context_cocoa_activate (GstGLContext * context, gboolean activate); static GstGLAPI gst_gl_context_cocoa_get_gl_api (GstGLContext * context); @@ -84,7 +84,7 @@ gst_gl_context_cocoa_new (void) static gboolean gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, - guintptr external_gl_context, GError **error) + GstGLContext *other_context, GError **error) { GstGLContextCocoa *context_cocoa = GST_GL_CONTEXT_COCOA (context); GstGLContextCocoaPrivate *priv = context_cocoa->priv; @@ -103,7 +103,10 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, }; priv->gl_context = nil; - priv->external_gl_context = (NSOpenGLContext *) external_gl_context; + if (other_context) + priv->external_gl_context = (NSOpenGLContext *) gst_gl_context_get_gl_context (other_context); + else + priv->external_gl_context = NULL; GSRegisterCurrentThread(); @@ -146,7 +149,9 @@ gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api, context_cocoa->priv->gl_context = glContext; [glView setOpenGLContext:glContext]; + #else + /* FIXME try to make context sharing work in GNUstep */ context_cocoa->priv->gl_context = [glView openGLContext]; #endif diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c index 3ef5075..6864dd0 100644 --- a/gst-libs/gst/gl/egl/gstglcontext_egl.c +++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c @@ -22,6 +22,10 @@ #include "config.h" #endif +/* FIXME: Sharing contexts requires the EGLDisplay & EGLConfig to be the same + * may need to box it. + */ + #include "gstglcontext_egl.h" #include @@ -33,7 +37,7 @@ #endif static gboolean gst_gl_context_egl_create_context (GstGLContext * context, - GstGLAPI gl_api, guintptr external_gl_context, GError ** error); + GstGLAPI gl_api, GstGLContext * other_context, GError ** error); static void gst_gl_context_egl_destroy_context (GstGLContext * context); static gboolean gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error); @@ -150,27 +154,40 @@ gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error) } static gboolean -gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GError ** error) +gst_gl_context_egl_choose_config (GstGLContextEGL * egl, + GstGLContext * other_context, GError ** error) { EGLint numConfigs; gint i = 0; EGLint config_attrib[20]; - config_attrib[i++] = EGL_SURFACE_TYPE; - config_attrib[i++] = EGL_WINDOW_BIT; - config_attrib[i++] = EGL_RENDERABLE_TYPE; - if (egl->gl_api & GST_GL_API_GLES2) - config_attrib[i++] = EGL_OPENGL_ES2_BIT; - else - config_attrib[i++] = EGL_OPENGL_BIT; - config_attrib[i++] = EGL_DEPTH_SIZE; - config_attrib[i++] = 16; - config_attrib[i++] = EGL_NONE; + if (other_context) { + GstGLContextEGL *other_context_egl = GST_GL_CONTEXT_EGL (other_context); + EGLint config_id; + + eglGetConfigAttrib (egl->egl_display, other_context_egl->egl_config, + EGL_CONFIG_ID, &config_id); + + config_attrib[i++] = EGL_CONFIG_ID; + config_attrib[i++] = config_id; + config_attrib[i++] = EGL_NONE; + } else { + config_attrib[i++] = EGL_SURFACE_TYPE; + config_attrib[i++] = EGL_WINDOW_BIT; + config_attrib[i++] = EGL_RENDERABLE_TYPE; + if (egl->gl_api & GST_GL_API_GLES2) + config_attrib[i++] = EGL_OPENGL_ES2_BIT; + else + config_attrib[i++] = EGL_OPENGL_BIT; + config_attrib[i++] = EGL_DEPTH_SIZE; + config_attrib[i++] = 16; + config_attrib[i++] = EGL_NONE; + } if (eglChooseConfig (egl->egl_display, config_attrib, &egl->egl_config, 1, &numConfigs)) { - GST_INFO ("config set: %ld, %ld", (gulong) egl->egl_config, - (gulong) numConfigs); + GST_INFO ("config set: %" G_GUINTPTR_FORMAT ", %u", + (guintptr) egl->egl_config, (unsigned int) numConfigs); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to set window configuration: %s", @@ -186,7 +203,7 @@ failure: static gboolean gst_gl_context_egl_create_context (GstGLContext * context, - GstGLAPI gl_api, guintptr external_gl_context, GError ** error) + GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextEGL *egl; GstGLWindow *window = NULL; @@ -197,19 +214,33 @@ gst_gl_context_egl_create_context (GstGLContext * context, EGLint minorVersion; const gchar *egl_exts; gboolean need_surface = TRUE; + guintptr external_gl_context = 0; egl = GST_GL_CONTEXT_EGL (context); window = gst_gl_context_get_window (context); - if ((gl_api & GST_GL_API_OPENGL) == GST_GL_API_NONE && - (gl_api & GST_GL_API_GLES2) == GST_GL_API_NONE) { + if (other_context) { + if (!GST_GL_IS_CONTEXT_EGL (other_context)) { + g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG, + "Cannot share context with non-EGL context"); + goto failure; + } + external_gl_context = gst_gl_context_get_gl_context (other_context); + } + + if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_GLES2)) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, - "xEGL supports opengl or gles2"); + "EGL supports opengl or gles2"); goto failure; } - egl->egl_display = - eglGetDisplay ((EGLNativeDisplayType) gst_gl_window_get_display (window)); + if (other_context) { + GstGLContextEGL *other_egl = (GstGLContextEGL *) other_context; + egl->egl_display = other_egl->egl_display; + } else { + egl->egl_display = eglGetDisplay ((EGLNativeDisplayType) + gst_gl_window_get_display (window)); + } if (eglInitialize (egl->egl_display, &majorVersion, &minorVersion)) { GST_INFO ("egl initialized, version: %d.%d", majorVersion, minorVersion); @@ -245,11 +276,12 @@ gst_gl_context_egl_create_context (GstGLContext * context, if (!eglBindAPI (EGL_OPENGL_API)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, - "Failed to bind OpenGL|ES API: %s", + "Failed to bind OpenGL API: %s", gst_gl_context_egl_get_error_string ()); goto failure; } + GST_INFO ("Using OpenGL"); egl->gl_api = GST_GL_API_OPENGL; } else if (gl_api & GST_GL_API_GLES2) { try_gles2: @@ -260,10 +292,11 @@ gst_gl_context_egl_create_context (GstGLContext * context, goto failure; } + GST_INFO ("Using OpenGL|ES 2.0"); egl->gl_api = GST_GL_API_GLES2; } - if (!gst_gl_context_egl_choose_config (egl, error)) { + if (!gst_gl_context_egl_choose_config (egl, other_context, error)) { g_assert (error == NULL || *error != NULL); goto failure; } @@ -281,7 +314,8 @@ gst_gl_context_egl_create_context (GstGLContext * context, (EGLContext) external_gl_context, context_attrib); if (egl->egl_context != EGL_NO_CONTEXT) { - GST_INFO ("gl context created: %ld", (gulong) egl->egl_context); + GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, + (guintptr) egl->egl_context); } else { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, @@ -292,17 +326,19 @@ gst_gl_context_egl_create_context (GstGLContext * context, egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS); - /* FIXME do we want a window vfunc ? */ + if (other_context == NULL) { + /* FIXME do we want a window vfunc ? */ #if GST_GL_HAVE_WINDOW_X11 - if (GST_GL_IS_WINDOW_X11 (context->window)) { - gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); - } + if (GST_GL_IS_WINDOW_X11 (context->window)) { + gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window); + } #endif #if GST_GL_HAVE_WINDOW_WIN32 - if (GST_GL_IS_WINDOW_WIN32 (context->window)) { - gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); - } + if (GST_GL_IS_WINDOW_WIN32 (context->window)) { + gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window); + } #endif + } window_handle = gst_gl_window_get_window_handle (window); diff --git a/gst-libs/gst/gl/gstglcontext.c b/gst-libs/gst/gl/gstglcontext.c index c2d20a7..f459de7 100644 --- a/gst-libs/gst/gl/gstglcontext.c +++ b/gst-libs/gst/gl/gstglcontext.c @@ -72,7 +72,7 @@ struct _GstGLContextPrivate gboolean created; gboolean alive; - guintptr external_gl_context; + GstGLContext *other_context; GstGLAPI gl_api; GError **error; }; @@ -299,7 +299,7 @@ gst_gl_context_get_window (GstGLContext * context) /* Create an opengl context (one context for one GstGLDisplay) */ gboolean gst_gl_context_create (GstGLContext * context, - guintptr external_gl_context, GError ** error) + GstGLContext * other_context, GError ** error) { gboolean alive = FALSE; @@ -310,7 +310,7 @@ gst_gl_context_create (GstGLContext * context, g_mutex_lock (&context->priv->render_lock); if (!context->priv->created) { - context->priv->external_gl_context = external_gl_context; + context->priv->other_context = other_context; context->priv->error = error; context->priv->gl_thread = g_thread_new ("gstglcontext", @@ -476,7 +476,7 @@ _parse_gl_api (const gchar * apis_s) } //gboolean -//gst_gl_context_create (GstGLContext * context, guintptr external_gl_context, GError ** error) +//gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error) static gpointer gst_gl_context_create_thread (GstGLContext * context) { @@ -492,12 +492,12 @@ gst_gl_context_create_thread (GstGLContext * context) gchar *user_api_string; const gchar *user_choice; GError **error; - guintptr external_gl_context; + GstGLContext *other_context; g_mutex_lock (&context->priv->render_lock); error = context->priv->error; - external_gl_context = context->priv->external_gl_context; + other_context = context->priv->other_context; context_class = GST_GL_CONTEXT_GET_CLASS (context); window_class = GST_GL_WINDOW_GET_CLASS (context->window); @@ -539,7 +539,7 @@ gst_gl_context_create_thread (GstGLContext * context) "compiled api support (%s)", user_api_string, compiled_api_s); if (!context_class->create_context (context, compiled_api & user_api, - external_gl_context, error)) { + other_context, error)) { g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_string); diff --git a/gst-libs/gst/gl/gstglcontext.h b/gst-libs/gst/gl/gstglcontext.h index 68d6f05..21db7e8 100644 --- a/gst-libs/gst/gl/gstglcontext.h +++ b/gst-libs/gst/gl/gstglcontext.h @@ -23,7 +23,7 @@ #include -#include +#include G_BEGIN_DECLS @@ -71,7 +71,7 @@ struct _GstGLContextClass { gboolean (*activate) (GstGLContext *context, gboolean activate); gboolean (*choose_format) (GstGLContext *context, GError **error); gboolean (*create_context) (GstGLContext *context, GstGLAPI gl_api, - guintptr external_gl_context, GError ** error); + GstGLContext *other_context, GError ** error); void (*destroy_context) (GstGLContext *context); void (*swap_buffers) (GstGLContext *context); @@ -88,8 +88,9 @@ gboolean gst_gl_context_activate (GstGLContext *context, gboolean a gpointer gst_gl_context_get_proc_address (GstGLContext *context, const gchar *name); GstGLPlatform gst_gl_context_get_platform (GstGLContext *context); GstGLAPI gst_gl_context_get_gl_api (GstGLContext *context); +guintptr gst_gl_context_get_gl_context (GstGLContext *context); -gboolean gst_gl_context_create (GstGLContext *context, guintptr external_gl_context, GError ** error); +gboolean gst_gl_context_create (GstGLContext *context, GstGLContext *other_context, GError ** error); gpointer gst_gl_context_default_get_proc_address (GstGLContext *context, const gchar *name); diff --git a/gst-libs/gst/gl/win32/gstglcontext_wgl.c b/gst-libs/gst/gl/win32/gstglcontext_wgl.c index 826ab44..88e35af 100644 --- a/gst-libs/gst/gl/win32/gstglcontext_wgl.c +++ b/gst-libs/gst/gl/win32/gstglcontext_wgl.c @@ -40,7 +40,7 @@ static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context, static gboolean gst_gl_context_wgl_activate (GstGLContext * context, gboolean activate); static gboolean gst_gl_context_wgl_create_context (GstGLContext * context, - GstGLAPI gl_api, guintptr external_gl_context, GError ** error); + GstGLAPI gl_api, GstGLContext * other_context, GError ** error); static void gst_gl_context_wgl_destroy_context (GstGLContext * context); GstGLAPI gst_gl_context_wgl_get_gl_api (GstGLContext * context); static gpointer gst_gl_context_wgl_get_proc_address (GstGLContext * context, @@ -84,23 +84,33 @@ gst_gl_context_wgl_new (void) static gboolean gst_gl_context_wgl_create_context (GstGLContext * context, - GstGLAPI gl_api, guintptr external_gl_context, GError ** error) + GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLWindow *window; GstGLContextWGL *context_wgl; + GstGLContextWGL *other_wgl = NULL; HDC device; context_wgl = GST_GL_CONTEXT_WGL (context); window = gst_gl_context_get_window (context); device = (HDC) gst_gl_window_get_display (window); + if (other_context) { + if (!GST_GL_IS_CONTEXT_WGL (other_context)) { + g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG, + "Cannot share context with a non-WGL context"); + goto failure; + } + other_wgl = (GstGLContextWGL *) other_context; + } + context_wgl->wgl_context = wglCreateContext (device); if (context_wgl->wgl_context) GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT, (guintptr) context_wgl->wgl_context); else { g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_CREATE_CONTEXT, - "failed to create glcontext:%lu", GetLastError ()); + "failed to create glcontext:0x%x", (unsigned int) GetLastError ()); goto failure; } g_assert (context_wgl->wgl_context); @@ -108,6 +118,15 @@ gst_gl_context_wgl_create_context (GstGLContext * context, GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT, (guintptr) context_wgl->wgl_context); + if (other_wgl) { + if (!wglShareLists (other_wgl->wgl_context, context_wgl->wgl_context)) { + g_set_error (error, GST_GL_WINDOW_ERROR, + GST_GL_WINDOW_ERROR_CREATE_CONTEXT, "failed to share contexts 0x%x", + (unsigned int) GetLastError ()); + goto failure; + } + } + gst_object_unref (window); return TRUE; diff --git a/gst-libs/gst/gl/x11/gstglcontext_glx.c b/gst-libs/gst/gl/x11/gstglcontext_glx.c index 86c9d8a..abfec94 100644 --- a/gst-libs/gst/gl/x11/gstglcontext_glx.c +++ b/gst-libs/gst/gl/x11/gstglcontext_glx.c @@ -25,6 +25,10 @@ #include "config.h" #endif +/* FIXME: Sharing contexts requires the Display to be the same. + * May need to box it + */ + #include #include "../gstgl_fwd.h" @@ -46,7 +50,7 @@ static void gst_gl_context_glx_swap_buffers (GstGLContext * context); static gboolean gst_gl_context_glx_activate (GstGLContext * context, gboolean activate); static gboolean gst_gl_context_glx_create_context (GstGLContext * - context, GstGLAPI gl_api, guintptr external_gl_context, GError ** error); + context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error); static void gst_gl_context_glx_destroy_context (GstGLContext * context); static gboolean gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error); @@ -129,7 +133,7 @@ _describe_fbconfig (Display * display, GLXFBConfig config) static gboolean gst_gl_context_glx_create_context (GstGLContext * context, - GstGLAPI gl_api, guintptr external_gl_context, GError ** error) + GstGLAPI gl_api, GstGLContext * other_context, GError ** error) { GstGLContextGLX *context_glx; GstGLWindow *window; @@ -138,11 +142,28 @@ gst_gl_context_glx_create_context (GstGLContext * context, const char *glx_exts; int x_error; Display *device; + guintptr external_gl_context = 0; context_glx = GST_GL_CONTEXT_GLX (context); window = gst_gl_context_get_window (context); window_x11 = GST_GL_WINDOW_X11 (window); - device = (Display *) gst_gl_window_get_display (window); + + if (other_context) { + GstGLWindow *other_window; + + if (!GST_GL_IS_CONTEXT_GLX (other_context)) { + g_set_error (error, GST_GL_WINDOW_ERROR, GST_GL_WINDOW_ERROR_WRONG_CONFIG, + "Cannot share context with non-GLX context"); + goto failure; + } + + other_window = gst_gl_context_get_window (other_context); + external_gl_context = gst_gl_context_get_gl_context (other_context); + device = (Display *) gst_gl_window_get_display (other_window); + gst_object_unref (other_window); + } else { + device = (Display *) gst_gl_window_get_display (window); + } glx_exts = glXQueryExtensionsString (device, DefaultScreen (device)); -- cgit v1.2.3