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);
+static GstGLPlatform gst_gl_context_cocoa_get_gl_platform (GstGLContext * context);
#define GST_GL_CONTEXT_COCOA_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT_COCOA, GstGLContextCocoaPrivate))
context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_activate);
context_class->get_gl_api =
GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_api);
+ context_class->get_gl_platform =
+ GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_platform);
#ifndef GNUSTEP
pool = [[NSAutoreleasePool alloc] init];
{
return GST_GL_API_OPENGL;
}
+
+static GstGLPlatform
+gst_gl_context_cocoa_get_gl_platform (GstGLContext * context)
+{
+ return GST_GL_API_COCOA;
+}
static void gst_gl_context_egl_swap_buffers (GstGLContext * context);
static guintptr gst_gl_context_egl_get_gl_context (GstGLContext * context);
static GstGLAPI gst_gl_context_egl_get_gl_api (GstGLContext * context);
+static GstGLPlatform gst_gl_context_egl_get_gl_platform (GstGLContext *
+ context);
static gpointer gst_gl_context_egl_get_proc_address (GstGLContext * context,
const gchar * name);
GST_DEBUG_FUNCPTR (gst_gl_context_egl_swap_buffers);
context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_api);
+ context_class->get_gl_platform =
+ GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform);
context_class->get_proc_address =
GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_proc_address);
}
const gchar *egl_exts;
gboolean need_surface = TRUE;
guintptr external_gl_context = 0;
+ guintptr native_display;
+ GstGLDisplay *display;
egl = GST_GL_CONTEXT_EGL (context);
window = gst_gl_context_get_window (context);
if (other_context) {
- if (!GST_GL_IS_CONTEXT_EGL (other_context)) {
+ if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) {
g_set_error (error, GST_GL_CONTEXT_ERROR,
GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
"Cannot share context with non-EGL context");
return GST_GL_CONTEXT_EGL (context)->gl_api;
}
+static GstGLPlatform
+gst_gl_context_egl_get_gl_platform (GstGLContext * context)
+{
+ return GST_GL_PLATFORM_EGL;
+}
+
static gpointer
gst_gl_context_egl_get_proc_address (GstGLContext * context, const gchar * name)
{
GError **error;
};
+typedef struct
+{
+ GstGLContext parent;
+
+ guintptr handle;
+ GstGLPlatform platform;
+ GstGLAPI available_apis;
+} GstGLWrappedContext;
+
+typedef struct
+{
+ GstGLContextClass parent;
+} GstGLWrappedContextClass;
+
+#define GST_GL_TYPE_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type())
+GType gst_gl_wrapped_context_get_type (void);
+G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
+ GST_GL_TYPE_CONTEXT);
+
+#define GST_GL_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WRAPPED_CONTEXT, GstGLWrappedContext))
+#define GST_GL_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_CONTEXT, GstGLContextClass))
+#define GST_GL_IS_WRAPPED_CONTEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WRAPPED_CONTEXT))
+#define GST_GL_IS_WRAPPED_CONTEXT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WRAPPED_CONTEXT))
+#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WRAPPED_CONTEXT, GstGLWrappedContextClass))
+
GQuark
gst_gl_context_error_quark (void)
{
G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize;
}
+static void
+_init_debug (void)
+{
+ static volatile gsize _init = 0;
+
+ if (g_once_init_enter (&_init)) {
+ GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
+ "glcontext element");
+ g_once_init_leave (&_init, 1);
+ }
+}
+
/**
* gst_gl_context_new:
* @display: a #GstGLDisplay
{
GstGLContext *context = NULL;
const gchar *user_choice;
- static volatile gsize _init = 0;
- if (g_once_init_enter (&_init)) {
- GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
- "glcontext element");
- g_once_init_leave (&_init, 1);
- }
+ _init_debug ();
user_choice = g_getenv ("GST_GL_PLATFORM");
GST_INFO ("creating a context, user choice:%s", user_choice);
return context;
}
+/**
+ * gst_gl_context_new_wrapped:
+ * @display: a #GstGLDisplay
+ * @handle: the OpenGL context to wrap
+ * @context_type: a #GstGLPlatform specifying the type of context in @handle
+ * @available_apis: a #GstGLAPI containing the available OpenGL apis in @handle
+ *
+ * Wraps an existing OpenGL context into a #GstGLContext.
+ *
+ * Returns: a #GstGLContext wrapping @handle
+ */
+GstGLContext *
+gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
+ GstGLPlatform context_type, GstGLAPI available_apis)
+{
+ GstGLContext *context;
+ GstGLWrappedContext *context_wrap = NULL;
+
+ _init_debug ();
+
+ context_wrap = g_object_new (GST_GL_TYPE_WRAPPED_CONTEXT, NULL);
+
+ if (!context_wrap) {
+ /* subclass returned a NULL context */
+ GST_ERROR ("Could not wrap existing context");
+
+ return NULL;
+ }
+
+ context = (GstGLContext *) context_wrap;
+
+ context->priv->display = gst_object_ref (display);
+ context_wrap->handle = handle;
+ context_wrap->platform = context_type;
+ context_wrap->available_apis = available_apis;
+
+ return context;
+}
+
static void
gst_gl_context_finalize (GObject * object)
{
GstGLContext *context = GST_GL_CONTEXT (object);
- gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
- gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
-
- if (context->priv->alive) {
- g_mutex_lock (&context->priv->render_lock);
- GST_INFO ("send quit gl window loop");
- gst_gl_window_quit (context->window);
- while (context->priv->alive) {
- g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
+ if (context->window) {
+ gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
+ gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
+
+ if (context->priv->alive) {
+ g_mutex_lock (&context->priv->render_lock);
+ GST_INFO ("send quit gl window loop");
+ gst_gl_window_quit (context->window);
+ while (context->priv->alive) {
+ g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
+ }
+ g_mutex_unlock (&context->priv->render_lock);
}
- g_mutex_unlock (&context->priv->render_lock);
- }
- gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
+ gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
+
+ if (context->priv->gl_thread) {
+ gpointer ret = g_thread_join (context->priv->gl_thread);
+ GST_INFO ("gl thread joined");
+ if (ret != NULL)
+ GST_ERROR ("gl thread returned a non-null pointer");
+ context->priv->gl_thread = NULL;
+ }
- if (context->priv->gl_thread) {
- gpointer ret = g_thread_join (context->priv->gl_thread);
- GST_INFO ("gl thread joined");
- if (ret != NULL)
- GST_ERROR ("gl thread returned a non-null pointer");
- context->priv->gl_thread = NULL;
+ gst_object_unref (context->window);
}
- gst_object_unref (context->window);
gst_object_unref (context->priv->display);
if (context->gl_vtable) {
GstGLContextClass *context_class;
g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), NULL);
context_class = GST_GL_CONTEXT_GET_CLASS (context);
g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);
gboolean
gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
{
+ g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), NULL);
+
/* we can't change the window while we are running */
if (context->priv->alive)
return FALSE;
{
g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
+ if (GST_GL_IS_WRAPPED_CONTEXT (context))
+ return NULL;
+
_ensure_window (context);
return gst_object_ref (context->window);
gboolean alive = FALSE;
g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE);
-
+ g_return_val_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context), FALSE);
_ensure_window (context);
g_mutex_lock (&context->priv->render_lock);
}
#endif
- _gst_gl_feature_check_ext_functions (context, 0, 0,
- (const gchar *) gl->GetString (GL_EXTENSIONS));
-
if (gl_major)
*gl_major = 2;
if (gl_minor)
return FALSE;
}
- _gst_gl_feature_check_ext_functions (context, maj, min,
- (const gchar *) gl->GetString (GL_EXTENSIONS));
-
if (gl_major)
*gl_major = maj;
if (gl_minor)
GstGLWindowClass *window_class;
GstGLDisplay *display;
GstGLFuncs *gl;
- gint gl_major = 0;
+ gint gl_major = 0, gl_minor = 0;
gboolean ret = FALSE;
GstGLAPI compiled_api, user_api;
gchar *api_string;
/* gl api specific code */
if (!ret && USING_OPENGL (display))
- ret = _create_context_opengl (context, &gl_major, NULL, error);
+ ret = _create_context_opengl (context, &gl_major, &gl_minor, error);
if (!ret && USING_GLES2 (display))
- ret = _create_context_gles2 (context, &gl_major, NULL, error);
+ ret = _create_context_gles2 (context, &gl_major, &gl_minor, error);
if (!ret)
goto failure;
+ _gst_gl_feature_check_ext_functions (context, gl_major, gl_minor,
+ (const gchar *) gl->GetString (GL_EXTENSIONS));
+
context->priv->alive = TRUE;
g_cond_signal (&context->priv->create_cond);
return result;
}
+/**
+ * gst_gl_context_get_gl_platform:
+ * @context: a #GstGLContext:
+ *
+ * Gets the OpenGL platform that used by @context.
+ *
+ * Returns: The platform specific backing OpenGL context
+ */
+GstGLPlatform
+gst_gl_context_get_gl_platform (GstGLContext * context)
+{
+ GstGLContextClass *context_class;
+
+ g_return_val_if_fail (GST_GL_IS_CONTEXT (context), 0);
+ context_class = GST_GL_CONTEXT_GET_CLASS (context);
+ g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
+
+ return context_class->get_gl_platform (context);
+}
+
/**
* gst_gl_context_get_display:
* @context: a #GstGLContext:
g_return_if_fail (GST_GL_IS_CONTEXT (context));
g_return_if_fail (func != NULL);
+ g_return_if_fail (!GST_GL_IS_WRAPPED_CONTEXT (context));
rdata.context = context;
rdata.data = data;
gst_object_unref (window);
}
+
+
+static GstGLAPI
+gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
+{
+ GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+ return context_wrap->available_apis;
+}
+
+static guintptr
+gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
+{
+ GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+ return context_wrap->handle;
+}
+
+static GstGLPlatform
+gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
+{
+ GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
+
+ return context_wrap->platform;
+}
+
+static gboolean
+gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
+{
+ g_assert_not_reached ();
+
+ return FALSE;
+}
+
+static void
+gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
+{
+ GstGLContextClass *context_class = (GstGLContextClass *) klass;
+
+ context_class->get_gl_context =
+ GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
+ context_class->get_gl_api =
+ GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
+ context_class->get_gl_platform =
+ GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
+ context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
+}
+
+static void
+gst_gl_wrapped_context_init (GstGLWrappedContext * context)
+{
+}
+
+/* Must be called in the gl thread */
+GstGLWrappedContext *
+gst_gl_wrapped_context_new (void)
+{
+ GstGLWrappedContext *context =
+ g_object_new (GST_GL_TYPE_WRAPPED_CONTEXT, NULL);
+
+ return context;
+}
*/
typedef void (*GstGLContextThreadFunc) (GstGLContext * context, gpointer data);
+#define GST_GL_CONTEXT_TYPE_GLX "gst.gl.context.GLX"
+#define GST_GL_CONTEXT_TYPE_EGL "gst.gl.context.EGL"
+#define GST_GL_CONTEXT_TYPE_WGL "gst.gl.context.WGL"
+
typedef enum
{
GST_GL_CONTEXT_ERROR_FAILED,
struct _GstGLContextClass {
GObjectClass parent_class;
- guintptr (*get_gl_context) (GstGLContext *context);
- GstGLAPI (*get_gl_api) (GstGLContext *context);
- gpointer (*get_proc_address) (GstGLContext *context, const gchar *name);
- gboolean (*activate) (GstGLContext *context, gboolean activate);
- gboolean (*choose_format) (GstGLContext *context, GError **error);
- gboolean (*create_context) (GstGLContext *context, GstGLAPI gl_api,
- GstGLContext *other_context, GError ** error);
- void (*destroy_context) (GstGLContext *context);
- void (*swap_buffers) (GstGLContext *context);
+ guintptr (*get_gl_context) (GstGLContext *context);
+ GstGLAPI (*get_gl_api) (GstGLContext *context);
+ GstGLPlatform (*get_gl_platform) (GstGLContext *context);
+ gpointer (*get_proc_address) (GstGLContext *context, const gchar *name);
+ gboolean (*activate) (GstGLContext *context, gboolean activate);
+ gboolean (*choose_format) (GstGLContext *context, GError **error);
+ gboolean (*create_context) (GstGLContext *context, GstGLAPI gl_api,
+ GstGLContext *other_context, GError ** error);
+ void (*destroy_context) (GstGLContext *context);
+ void (*swap_buffers) (GstGLContext *context);
/*< private >*/
gpointer _reserved[GST_PADDING];
/* methods */
GstGLContext * gst_gl_context_new (GstGLDisplay *display);
+GstGLContext * gst_gl_context_new_wrapped (GstGLDisplay *display,
+ guintptr handle,
+ GstGLPlatform context_type,
+ GstGLAPI available_apis);
gboolean gst_gl_context_activate (GstGLContext *context, gboolean activate);
GstGLDisplay * gst_gl_context_get_display (GstGLContext *context);
gpointer gst_gl_context_get_proc_address (GstGLContext *context, const gchar *name);
-GstGLPlatform gst_gl_context_get_platform (GstGLContext *context);
+GstGLPlatform gst_gl_context_get_gl_platform (GstGLContext *context);
GstGLAPI gst_gl_context_get_gl_api (GstGLContext *context);
guintptr gst_gl_context_get_gl_context (GstGLContext *context);
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 GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext *
+ context);
static gpointer gst_gl_context_wgl_get_proc_address (GstGLContext * context,
const gchar * name);
context_class->get_proc_address =
GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_proc_address);
context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_api);
+ context_class->get_gl_platform =
+ GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform);
}
static void
{
GstGLWindow *window;
GstGLContextWGL *context_wgl;
- GstGLContextWGL *other_wgl = NULL;
+ HGLRC external_gl_context = NULL;
HDC device;
context_wgl = GST_GL_CONTEXT_WGL (context);
"Cannot share context with a non-WGL context");
goto failure;
}
- other_wgl = (GstGLContextWGL *) other_context;
+ external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context);
}
context_wgl->wgl_context = wglCreateContext (device);
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)) {
+ if (external_gl_context) {
+ if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
g_set_error (error, GST_GL_CONTEXT_ERROR,
GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to share contexts 0x%x",
(unsigned int) GetLastError ());
return GST_GL_API_OPENGL;
}
+static GstGLPlatform
+gst_gl_context_wgl_get_gl_platform (GstGLContext * context)
+{
+ return GST_GL_PLATFORM_WGL;
+}
+
static gpointer
gst_gl_context_wgl_get_proc_address (GstGLContext * context, const gchar * name)
{
static gboolean gst_gl_context_glx_choose_format (GstGLContext *
context, GError ** error);
GstGLAPI gst_gl_context_glx_get_gl_api (GstGLContext * context);
+static GstGLPlatform gst_gl_context_glx_get_gl_platform (GstGLContext *
+ context);
static gpointer gst_gl_context_glx_get_proc_address (GstGLContext * context,
const gchar * name);
GST_DEBUG_FUNCPTR (gst_gl_context_glx_swap_buffers);
context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_api);
+ context_class->get_gl_platform =
+ GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform);
context_class->get_proc_address =
GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_proc_address);
}
window_x11 = GST_GL_WINDOW_X11 (window);
if (other_context) {
- GstGLWindow *other_window;
-
- if (!GST_GL_IS_CONTEXT_GLX (other_context)) {
+ if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) {
g_set_error (error, GST_GL_CONTEXT_ERROR,
GST_GL_CONTEXT_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);
}
+ device = (Display *) gst_gl_window_get_display (window);
glx_exts = glXQueryExtensionsString (device, DefaultScreen (device));
create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts);
return context_glx->priv->context_api;
}
+static GstGLPlatform
+gst_gl_context_glx_get_gl_platform (GstGLContext * context)
+{
+ return GST_GL_PLATFORM_GLX;
+}
+
static gpointer
gst_gl_context_glx_get_proc_address (GstGLContext * context, const gchar * name)
{
gl->DeleteTextures (1, &tex);;
gst_object_unref (fbo);
#if GST_GL_HAVE_GLES2
- gst_object_unref (shader);
+ if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2)
+ gst_object_unref (shader);
#endif
}
GST_END_TEST;
+GST_START_TEST (test_wrapped_context)
+{
+ GstGLContext *context, *other_context, *wrapped_context;
+ GstGLWindow *window, *other_window;
+ GError *error = NULL;
+ gint i = 0;
+ guintptr handle;
+ GstGLPlatform platform;
+ GstGLAPI apis;
+
+ display = gst_gl_display_new ();
+ context = gst_gl_context_new (display);
+
+ window = gst_gl_window_new (display);
+ gst_gl_context_set_window (context, window);
+
+ gst_gl_context_create (context, 0, &error);
+
+ fail_if (error != NULL, "Error creating master context %s\n",
+ error ? error->message : "Unknown Error");
+
+ handle = gst_gl_context_get_gl_context (context);
+ platform = gst_gl_context_get_gl_platform (context);
+ apis = gst_gl_context_get_gl_api (context);
+
+ wrapped_context =
+ gst_gl_context_new_wrapped (display, handle, platform, apis);
+
+ other_context = gst_gl_context_new (display);
+ other_window = gst_gl_window_new (display);
+ gst_gl_context_set_window (other_context, other_window);
+
+ gst_gl_context_create (other_context, wrapped_context, &error);
+
+ fail_if (error != NULL, "Error creating secondary context %s\n",
+ error ? error->message : "Unknown Error");
+
+ /* make the window visible */
+ gst_gl_window_draw (window, 320, 240);
+
+ gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (init), context);
+
+ while (i < 1000) {
+ gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (draw_tex),
+ context);
+ gst_gl_window_send_message (window, GST_GL_WINDOW_CB (draw_render),
+ context);
+ i++;
+ }
+
+ gst_gl_window_send_message (other_window, GST_GL_WINDOW_CB (deinit), context);
+
+ gst_object_unref (window);
+ gst_object_unref (other_window);
+ gst_object_unref (other_context);
+ gst_object_unref (context);
+}
+
+GST_END_TEST;
+
Suite *
gst_gl_memory_suite (void)
suite_add_tcase (s, tc_chain);
tcase_add_checked_fixture (tc_chain, setup, teardown);
tcase_add_test (tc_chain, test_share);
+ tcase_add_test (tc_chain, test_wrapped_context);
return s;
}