3 * Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:gstglcontext
23 * @short_description: OpenGL context abstraction
24 * @title: GstGLContext
25 * @see_also: #GstGLDisplay, #GstGLWindow
27 * #GstGLContext wraps an OpenGL context object in a uniform API. As a result
28 * of the limitation on OpenGL context, this object is not thread safe unless
29 * specified and must only be activated in a single thread.
31 * Environment variables:
32 * - `GST_GL_API`: select which OpenGL API to create and OpenGL context for.
33 * Depending on the platform, the available values are
34 * 'opengl', 'opengl3' (core profile), and 'gles2'. See the
35 * the #GstGLAPI enumeration for more details.
36 * - `GST_GL_PLATFORM`: select which OpenGL platform to create an OpenGL
37 * context with. Depending on the platform and the
38 * dependencies available build-time, the available values
39 * are, 'glx', 'egl', 'cgl', 'wgl', and 'eagl'
40 * - `GST_GL_CONFIG`: select the configuration used for creating the OpenGL
41 * context and OpenGL surface. Written out as a GstStructure
42 * that has been serialized to string. e.g.
43 * `GST_GL_CONFIG="gst-gl-context-config,red-size=8,green-size=8,blue-size=8,alpha-size=8,depth-size=16"`.
44 * Not all platforms will support the same level of
52 #if defined(ANDROID) || defined(__ANDROID__)
53 /* Avoid a linker error with _isoc99_sscanf() when building a shared library
59 #include "gstglcontext.h"
60 #include <gst/gl/gl.h>
66 #include "gstglcontext_private.h"
67 #include "gstglfeature.h"
68 #include "gstglfeature_private.h"
69 #include "gstglfuncs.h"
71 #ifndef GL_NUM_EXTENSIONS
72 #define GL_NUM_EXTENSIONS 0x0000821d
75 #if GST_GL_HAVE_PLATFORM_GLX
76 #include "x11/gstglcontext_glx.h"
78 #if GST_GL_HAVE_PLATFORM_EGL
79 #include "egl/gstglcontext_egl.h"
81 #if GST_GL_HAVE_PLATFORM_CGL
82 #include "cocoa/gstglcontext_cocoa.h"
84 #if GST_GL_HAVE_PLATFORM_WGL
85 #include "wgl/gstglcontext_wgl.h"
87 #if GST_GL_HAVE_PLATFORM_EAGL
88 #include "eagl/gstglcontext_eagl.h"
91 extern void _gst_gl_debug_enable (GstGLContext * context);
93 static GPrivate current_context_key;
95 static GModule *module_self;
96 static GOnce module_self_gonce = G_ONCE_INIT;
98 #if GST_GL_HAVE_OPENGL
99 static GOnce module_opengl_gonce = G_ONCE_INIT;
100 static GModule *module_opengl;
103 load_opengl_module (gpointer user_data)
105 #ifdef GST_GL_LIBGL_MODULE_NAME
106 module_opengl = g_module_open (GST_GL_LIBGL_MODULE_NAME, G_MODULE_BIND_LAZY);
108 /* On Linux the .so is only in -dev packages, try with a real soname
109 * Proper compilers will optimize away the strcmp */
110 if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
111 module_opengl = g_module_open ("libGL.so.1", G_MODULE_BIND_LAZY);
112 else if (g_strcmp0 (G_MODULE_SUFFIX, "dll") == 0)
113 module_opengl = g_module_open ("opengl32.dll", G_MODULE_BIND_LAZY);
115 /* This automatically handles the suffix and even .la files */
117 module_opengl = g_module_open ("libGL", G_MODULE_BIND_LAZY);
124 #if GST_GL_HAVE_GLES2
125 static GOnce module_gles2_gonce = G_ONCE_INIT;
126 static GModule *module_gles2;
129 load_gles2_module (gpointer user_data)
131 #ifdef GST_GL_LIBGLESV2_MODULE_NAME
133 g_module_open (GST_GL_LIBGLESV2_MODULE_NAME, G_MODULE_BIND_LAZY);
135 /* On Linux the .so is only in -dev packages, try with a real soname
136 * Proper compilers will optimize away the strcmp */
137 if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
138 module_gles2 = g_module_open ("libGLESv2.so.2", G_MODULE_BIND_LAZY);
140 /* This automatically handles the suffix and even .la files */
142 module_gles2 = g_module_open ("libGLESv2", G_MODULE_BIND_LAZY);
151 load_self_module (gpointer user_data)
153 module_self = g_module_open (NULL, G_MODULE_BIND_LAZY);
158 /* Context sharedness is tracked by a refcounted pointer stored in each context
159 * object to track complex creation/deletion scenarios. As a result,
160 * sharedness can only be successfully validated between two GstGLContext's
161 * where one is not a wrapped context.
163 * As there is no API at the winsys level to tell whether two OpenGL contexts
164 * can share GL resources, this is the next best thing.
166 * XXX: we may need a way to associate two wrapped GstGLContext's as being
167 * shared however I have not come across a use case that requires this yet.
169 struct ContextShareGroup
174 static struct ContextShareGroup *
175 _context_share_group_new (void)
177 struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1);
184 static struct ContextShareGroup *
185 _context_share_group_ref (struct ContextShareGroup *share)
187 g_atomic_int_inc (&share->refcount);
192 _context_share_group_unref (struct ContextShareGroup *share)
194 if (g_atomic_int_dec_and_test (&share->refcount))
199 _context_share_group_is_shared (struct ContextShareGroup *share)
201 return g_atomic_int_get (&share->refcount) > 1;
204 #define GST_CAT_DEFAULT gst_gl_context_debug
205 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
206 GST_DEBUG_CATEGORY_STATIC (gst_gl_debug);
208 static void _init_debug (void);
210 static gpointer gst_gl_context_create_thread (GstGLContext * context);
211 static void gst_gl_context_finalize (GObject * object);
212 static void gst_gl_context_default_get_gl_platform_version (GstGLContext *
213 context, gint * major, gint * minor);
215 struct _GstGLContextPrivate
218 GThread *active_thread;
228 GWeakRef other_context_ref;
229 struct ContextShareGroup *sharegroup;
236 GstStructure *requested_config;
244 GstGLPlatform platform;
245 GstGLAPI available_apis;
246 } GstGLWrappedContext;
250 GstGLContextClass parent;
251 } GstGLWrappedContextClass;
253 #define gst_gl_context_parent_class parent_class
254 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLContext, gst_gl_context,
257 G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
258 GST_TYPE_GL_CONTEXT);
261 * gst_gl_context_error_quark:
263 * Returns: the quark used for #GstGLContext in #GError's
266 gst_gl_context_error_quark (void)
268 return g_quark_from_static_string ("gst-gl-context-error-quark");
272 _ensure_window (GstGLContext * context)
279 window = gst_gl_display_create_window (context->display);
281 gst_gl_context_set_window (context, window);
283 gst_object_unref (window);
287 gst_gl_context_init (GstGLContext * context)
289 context->priv = gst_gl_context_get_instance_private (context);
291 context->window = NULL;
292 context->gl_vtable = g_slice_alloc0 (sizeof (GstGLFuncs));
294 g_mutex_init (&context->priv->render_lock);
296 g_cond_init (&context->priv->create_cond);
297 g_cond_init (&context->priv->destroy_cond);
298 context->priv->created = FALSE;
300 g_weak_ref_init (&context->priv->other_context_ref, NULL);
304 gst_gl_context_class_init (GstGLContextClass * klass)
306 klass->get_proc_address =
307 GST_DEBUG_FUNCPTR (gst_gl_context_default_get_proc_address);
308 klass->get_gl_platform_version =
309 GST_DEBUG_FUNCPTR (gst_gl_context_default_get_gl_platform_version);
311 G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize;
319 static gsize _init = 0;
321 if (g_once_init_enter (&_init)) {
322 GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
323 "glcontext element");
324 GST_DEBUG_CATEGORY_INIT (gst_gl_debug, "gldebug", 0, "OpenGL Debugging");
325 g_once_init_leave (&_init, 1);
330 * gst_gl_context_new:
331 * @display: a #GstGLDisplay
333 * Create a new #GstGLContext with the specified @display
335 * Returns: a new #GstGLContext
340 gst_gl_context_new (GstGLDisplay * display)
342 GstGLContext *context = NULL;
343 const gchar *user_choice;
347 user_choice = g_getenv ("GST_GL_PLATFORM");
348 GST_INFO ("creating a context for display %" GST_PTR_FORMAT
349 ", user choice:%s", display, user_choice);
350 #if GST_GL_HAVE_PLATFORM_CGL
351 if (!context && (!user_choice || g_strstr_len (user_choice, 3, "cgl")))
352 context = GST_GL_CONTEXT (gst_gl_context_cocoa_new (display));
354 #if GST_GL_HAVE_PLATFORM_GLX
355 if (!context && (!user_choice || g_strstr_len (user_choice, 3, "glx")))
356 context = GST_GL_CONTEXT (gst_gl_context_glx_new (display));
358 #if GST_GL_HAVE_PLATFORM_WGL
359 if (!context && (!user_choice || g_strstr_len (user_choice, 3, "wgl")))
360 context = GST_GL_CONTEXT (gst_gl_context_wgl_new (display));
362 #if GST_GL_HAVE_PLATFORM_EAGL
363 if (!context && (!user_choice || g_strstr_len (user_choice, 4, "eagl")))
364 context = GST_GL_CONTEXT (gst_gl_context_eagl_new (display));
366 #if GST_GL_HAVE_PLATFORM_EGL
367 if (!context && (!user_choice || g_strstr_len (user_choice, 3, "egl")))
368 context = GST_GL_CONTEXT (gst_gl_context_egl_new (display));
372 /* subclass returned a NULL context */
373 GST_WARNING ("Could not create context. user specified %s",
374 user_choice ? user_choice : "(null)");
379 context->display = gst_object_ref (display);
381 GST_DEBUG_OBJECT (context,
382 "Done creating context for display %" GST_PTR_FORMAT " (user_choice:%s)",
383 display, user_choice);
389 * gst_gl_context_new_wrapped:
390 * @display: a #GstGLDisplay
391 * @handle: the OpenGL context to wrap
392 * @context_type: a #GstGLPlatform specifying the type of context in @handle
393 * @available_apis: a #GstGLAPI containing the available OpenGL apis in @handle
395 * Wraps an existing OpenGL context into a #GstGLContext.
397 * Note: The caller is responsible for ensuring that the OpenGL context
398 * represented by @handle stays alive while the returned #GstGLContext is
401 * @context_type must not be %GST_GL_PLATFORM_NONE or %GST_GL_PLATFORM_ANY
403 * @available_apis must not be %GST_GL_API_NONE or %GST_GL_API_ANY
405 * Returns: (transfer full) (nullable): a #GstGLContext wrapping @handle
410 gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
411 GstGLPlatform context_type, GstGLAPI available_apis)
413 GstGLContext *context;
414 GstGLWrappedContext *context_wrap = NULL;
415 GstGLContextClass *context_class;
416 GstGLAPI display_api;
420 g_return_val_if_fail (GST_IS_GL_DISPLAY (display), NULL);
421 g_return_val_if_fail (handle != 0, NULL);
422 g_return_val_if_fail (available_apis != GST_GL_API_ANY, NULL);
423 g_return_val_if_fail (available_apis != GST_GL_API_NONE, NULL);
424 g_return_val_if_fail (context_type != GST_GL_PLATFORM_NONE, NULL);
425 g_return_val_if_fail (context_type != GST_GL_PLATFORM_ANY, NULL);
427 display_api = gst_gl_display_get_gl_api (display);
428 g_return_val_if_fail ((display_api & available_apis) != GST_GL_API_NONE,
431 context_wrap = g_object_new (GST_TYPE_GL_WRAPPED_CONTEXT, NULL);
432 gst_object_ref_sink (context_wrap);
434 context = (GstGLContext *) context_wrap;
436 context->display = gst_object_ref (display);
437 context->priv->sharegroup = _context_share_group_new ();
438 context_wrap->handle = handle;
439 context_wrap->platform = context_type;
440 context_wrap->available_apis = available_apis;
442 context_class = GST_GL_CONTEXT_GET_CLASS (context);
444 #if GST_GL_HAVE_PLATFORM_GLX
445 if (context_type == GST_GL_PLATFORM_GLX) {
446 context_class->get_current_context = gst_gl_context_glx_get_current_context;
447 context_class->get_proc_address = gst_gl_context_glx_get_proc_address;
450 #if GST_GL_HAVE_PLATFORM_EGL
451 if (context_type == GST_GL_PLATFORM_EGL) {
452 context_class->get_current_context = gst_gl_context_egl_get_current_context;
453 context_class->get_proc_address = gst_gl_context_egl_get_proc_address;
456 #if GST_GL_HAVE_PLATFORM_CGL
457 if (context_type == GST_GL_PLATFORM_CGL) {
458 context_class->get_current_context =
459 gst_gl_context_cocoa_get_current_context;
460 context_class->get_proc_address = gst_gl_context_default_get_proc_address;
463 #if GST_GL_HAVE_PLATFORM_WGL
464 if (context_type == GST_GL_PLATFORM_WGL) {
465 context_class->get_current_context = gst_gl_context_wgl_get_current_context;
466 context_class->get_proc_address = gst_gl_context_wgl_get_proc_address;
469 #if GST_GL_HAVE_PLATFORM_EAGL
470 if (context_type == GST_GL_PLATFORM_EAGL) {
471 context_class->get_current_context =
472 gst_gl_context_eagl_get_current_context;
473 context_class->get_proc_address = gst_gl_context_default_get_proc_address;
477 if (!context_class->get_current_context) {
478 /* we don't have API support */
479 gst_object_unref (context);
487 * gst_gl_context_get_current_gl_context:
488 * @context_type: a #GstGLPlatform specifying the type of context to retrieve
490 * Returns: (nullable): The OpenGL context handle current in the calling thread or %NULL
495 gst_gl_context_get_current_gl_context (GstGLPlatform context_type)
501 #if GST_GL_HAVE_PLATFORM_GLX
502 if (!handle && (context_type & GST_GL_PLATFORM_GLX) != 0)
503 handle = gst_gl_context_glx_get_current_context ();
505 #if GST_GL_HAVE_PLATFORM_EGL
506 if (!handle && (context_type & GST_GL_PLATFORM_EGL) != 0)
507 handle = gst_gl_context_egl_get_current_context ();
509 #if GST_GL_HAVE_PLATFORM_CGL
510 if (!handle && (context_type & GST_GL_PLATFORM_CGL) != 0)
511 handle = gst_gl_context_cocoa_get_current_context ();
513 #if GST_GL_HAVE_PLATFORM_WGL
514 if (!handle && (context_type & GST_GL_PLATFORM_WGL) != 0)
515 handle = gst_gl_context_wgl_get_current_context ();
517 #if GST_GL_HAVE_PLATFORM_EAGL
518 if (!handle && (context_type & GST_GL_PLATFORM_EAGL) != 0)
519 handle = gst_gl_context_eagl_get_current_context ();
523 GST_WARNING ("Could not retrieve current context");
529 * gst_gl_context_get_proc_address_with_platform:
530 * @context_type: a #GstGLPlatform
531 * @gl_api: a #GstGLAPI
532 * @name: the name of the function to retrieve
534 * Attempts to use the @context_type specific GetProcAddress implementations
537 * See also gst_gl_context_get_proc_address().
539 * Returns: (nullable): a function pointer for @name, or %NULL
544 gst_gl_context_get_proc_address_with_platform (GstGLPlatform context_type,
545 GstGLAPI gl_api, const gchar * name)
549 #if GST_GL_HAVE_PLATFORM_GLX
550 if (!ret && (context_type & GST_GL_PLATFORM_GLX) != 0)
551 ret = gst_gl_context_glx_get_proc_address (gl_api, name);
553 #if GST_GL_HAVE_PLATFORM_EGL
554 if (!ret && (context_type & GST_GL_PLATFORM_EGL) != 0)
555 ret = gst_gl_context_egl_get_proc_address (gl_api, name);
557 #if GST_GL_HAVE_PLATFORM_WGL
558 if (!ret && (context_type & GST_GL_PLATFORM_WGL) != 0)
559 ret = gst_gl_context_wgl_get_proc_address (gl_api, name);
561 /* CGL and EAGL rely on the default impl */
564 ret = gst_gl_context_default_get_proc_address (gl_api, name);
570 * gst_gl_context_get_current_gl_api:
571 * @platform: the #GstGLPlatform to retrieve the API for
572 * @major: (out) (allow-none): the major version
573 * @minor: (out) (allow-none): the minor version
575 * If an error occurs, @major and @minor are not modified and %GST_GL_API_NONE is
578 * Returns: The version supported by the OpenGL context current in the calling
579 * thread or %GST_GL_API_NONE
584 gst_gl_context_get_current_gl_api (GstGLPlatform platform, guint * major,
587 const GLubyte *(GSTGLAPI * GetString) (GLenum name);
588 #if GST_GL_HAVE_OPENGL
589 void (GSTGLAPI * GetIntegerv) (GLenum name, GLuint * n);
591 const gchar *version;
593 GstGLAPI ret = (1U << 31);
597 while (ret != GST_GL_API_NONE) {
598 /* FIXME: attempt to delve into the platform specific GetProcAddress */
600 gst_gl_context_get_proc_address_with_platform (platform, ret,
602 #if GST_GL_HAVE_OPENGL
604 gst_gl_context_get_proc_address_with_platform (platform, ret,
611 version = (const gchar *) GetString (GL_VERSION);
615 /* strlen (x.x) == 3 */
616 n = strlen (version);
620 if (g_strstr_len (version, 9, "OpenGL ES")) {
621 /* strlen (OpenGL ES x.x) == 13 */
625 sscanf (&version[10], "%d.%d", &maj, &min);
627 if (maj <= 0 || min < 0)
631 ret = GST_GL_API_GLES1;
633 } else if (maj == 2 || maj == 3) {
634 ret = GST_GL_API_GLES2;
640 sscanf (version, "%d.%d", &maj, &min);
642 if (maj <= 0 || min < 0)
645 #if GST_GL_HAVE_OPENGL
646 if (GetIntegerv && (maj > 3 || (maj == 3 && min > 1))) {
647 GLuint context_flags = 0;
649 ret = GST_GL_API_NONE;
650 GetIntegerv (GL_CONTEXT_PROFILE_MASK, &context_flags);
651 if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT)
652 ret |= GST_GL_API_OPENGL3;
653 if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
654 ret |= GST_GL_API_OPENGL;
658 ret = GST_GL_API_OPENGL;
663 /* iterate through the apis */
667 if (ret == GST_GL_API_NONE)
668 return GST_GL_API_NONE;
679 gst_gl_context_finalize (GObject * object)
681 GstGLContext *context = GST_GL_CONTEXT (object);
683 if (context->window) {
684 gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
685 gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
687 g_mutex_lock (&context->priv->render_lock);
688 if (context->priv->alive) {
689 GST_INFO_OBJECT (context, "send quit gl window loop");
690 gst_gl_window_quit (context->window);
692 GST_INFO_OBJECT (context, "joining gl thread");
693 while (context->priv->alive)
694 g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
695 GST_INFO_OBJECT (context, "gl thread joined");
697 if (context->priv->gl_thread) {
698 g_thread_unref (context->priv->gl_thread);
699 context->priv->gl_thread = NULL;
702 g_mutex_unlock (&context->priv->render_lock);
704 gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
705 gst_object_unref (context->window);
706 context->window = NULL;
709 if (context->priv->active_thread) {
710 g_thread_unref (context->priv->active_thread);
711 context->priv->active_thread = NULL;
714 if (context->priv->gl_thread) {
715 g_thread_unref (context->priv->gl_thread);
716 context->priv->gl_thread = NULL;
719 if (context->priv->sharegroup) {
720 _context_share_group_unref (context->priv->sharegroup);
721 context->priv->sharegroup = NULL;
724 if (context->display) {
725 gst_object_unref (context->display);
726 context->display = NULL;
729 if (context->gl_vtable) {
730 g_slice_free (GstGLFuncs, context->gl_vtable);
731 context->gl_vtable = NULL;
734 if (context->priv->requested_config)
735 gst_structure_free (context->priv->requested_config);
736 context->priv->requested_config = NULL;
738 g_mutex_clear (&context->priv->render_lock);
740 g_cond_clear (&context->priv->create_cond);
741 g_cond_clear (&context->priv->destroy_cond);
743 g_free (context->priv->gl_exts);
744 g_weak_ref_clear (&context->priv->other_context_ref);
746 GST_DEBUG_OBJECT (context, "End of finalize");
747 G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object);
751 * gst_gl_context_activate:
752 * @context: a #GstGLContext
753 * @activate: %TRUE to activate, %FALSE to deactivate
755 * (De)activate the OpenGL context represented by this @context.
757 * In OpenGL terms, calls eglMakeCurrent or similar with this context and the
758 * currently set window. See gst_gl_context_set_window() for details.
760 * Returns: Whether the activation succeeded
765 gst_gl_context_activate (GstGLContext * context, gboolean activate)
767 GstGLContextClass *context_class;
770 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
771 context_class = GST_GL_CONTEXT_GET_CLASS (context);
772 g_return_val_if_fail (context_class->activate != NULL, FALSE);
774 GST_DEBUG_OBJECT (context, "activate:%d", activate);
776 GST_OBJECT_LOCK (context);
777 result = context_class->activate (context, activate);
779 if (result && activate) {
780 GThread *old_thread = context->priv->active_thread;
781 context->priv->active_thread = g_thread_ref (g_thread_self ());
783 g_thread_unref (old_thread);
786 g_private_set (¤t_context_key, context);
788 if (context->priv->active_thread) {
789 g_thread_unref (context->priv->active_thread);
790 context->priv->active_thread = NULL;
792 g_private_set (¤t_context_key, NULL);
794 GST_OBJECT_UNLOCK (context);
800 * gst_gl_context_get_thread:
801 * @context: a #GstGLContext
803 * Returns: (transfer full) (nullable): The #GThread, @context is current in or NULL
808 gst_gl_context_get_thread (GstGLContext * context)
812 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
814 GST_OBJECT_LOCK (context);
815 ret = context->priv->active_thread;
818 GST_OBJECT_UNLOCK (context);
824 * gst_gl_context_get_gl_api:
825 * @context: a #GstGLContext
827 * Get the currently enabled OpenGL api.
829 * The currently available API may be limited by the #GstGLDisplay in use and/or
830 * the #GstGLWindow chosen.
832 * Returns: the available OpenGL api
837 gst_gl_context_get_gl_api (GstGLContext * context)
839 GstGLContextClass *context_class;
841 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), GST_GL_API_NONE);
842 context_class = GST_GL_CONTEXT_GET_CLASS (context);
843 g_return_val_if_fail (context_class->get_gl_api != NULL, GST_GL_API_NONE);
845 return context_class->get_gl_api (context);
849 * gst_gl_context_get_proc_address:
850 * @context: a #GstGLContext
851 * @name: an opengl function name
853 * Get a function pointer to a specified opengl function, @name. If the the
854 * specific function does not exist, NULL is returned instead.
856 * Platform specific functions (names starting 'egl', 'glX', 'wgl', etc) can also
857 * be retrieved using this method.
859 * Note: This function may return valid function pointers that may not be valid
860 * to call in @context. The caller is responsible for ensuring that the
861 * returned function is a valid function to call in @context by either checking
862 * the OpenGL API and version or for an appropriate OpenGL extension.
864 * Note: On success, you need to cast the returned function pointer to the
865 * correct type to be able to call it correctly. On 32-bit Windows, this will
866 * include the `GSTGLAPI` identifier to use the correct calling convention.
869 * |[<!-- language="C" -->
870 * void (GSTGLAPI *PFN_glGetIntegerv) (GLenum name, GLint * ret)
873 * Returns: (nullable): a function pointer or %NULL
878 gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
881 GstGLContextClass *context_class;
884 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
885 context_class = GST_GL_CONTEXT_GET_CLASS (context);
886 g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);
888 gl_api = gst_gl_context_get_gl_api (context);
889 ret = context_class->get_proc_address (gl_api, name);
895 * gst_gl_context_default_get_proc_address:
896 * @gl_api: a #GstGLAPI
897 * @name: then function to get the address of
899 * A default implementation of the various GetProcAddress functions that looks
900 * for @name in the OpenGL shared libraries or in the current process.
902 * See also: gst_gl_context_get_proc_address()
904 * Returns: (nullable): an address pointing to @name or %NULL
909 gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar * name)
913 /* First try to load symbol from the selected GL API for this context */
914 #if GST_GL_HAVE_GLES2
915 if (!ret && (gl_api & GST_GL_API_GLES2)) {
916 g_once (&module_gles2_gonce, load_gles2_module, NULL);
918 g_module_symbol (module_gles2, name, &ret);
922 #if GST_GL_HAVE_OPENGL
923 if (!ret && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
924 g_once (&module_opengl_gonce, load_opengl_module, NULL);
926 g_module_symbol (module_opengl, name, &ret);
930 /* Otherwise fall back to the current module */
931 g_once (&module_self_gonce, load_self_module, NULL);
933 g_module_symbol (module_self, name, &ret);
939 * gst_gl_context_set_window:
940 * @context: a #GstGLContext
941 * @window: (transfer full): a #GstGLWindow
943 * Set's the current window on @context to @window. The window can only be
944 * changed before gst_gl_context_create() has been called and the @window is not
947 * Returns: Whether the window was successfully updated
952 gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
954 g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
956 GST_DEBUG_OBJECT (context, "window:%" GST_PTR_FORMAT, window);
958 /* we can't change the window while we are running */
959 if (context->priv->alive)
963 g_weak_ref_set (&window->context_ref, context);
966 gst_object_unref (context->window);
968 context->window = window ? gst_object_ref (window) : NULL;
974 * gst_gl_context_get_window:
975 * @context: a #GstGLContext
977 * Returns: (transfer full) (nullable): the currently set window
982 gst_gl_context_get_window (GstGLContext * context)
984 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
986 if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
987 GST_WARNING_OBJECT (context, "context is not toplevel, returning NULL");
991 _ensure_window (context);
993 return gst_object_ref (context->window);
997 * gst_gl_context_can_share:
998 * @context: a #GstGLContext
999 * @other_context: another #GstGLContext
1001 * Note: This will always fail for two wrapped #GstGLContext's
1003 * Returns: whether @context and @other_context are able to share OpenGL
1009 gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
1011 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1012 g_return_val_if_fail (GST_IS_GL_CONTEXT (other_context), FALSE);
1014 /* check if the contexts are descendants or the root nodes are the same */
1015 return context->priv->sharegroup != NULL
1016 && context->priv->sharegroup == other_context->priv->sharegroup;
1020 * gst_gl_context_create:
1021 * @context: a #GstGLContext:
1022 * @other_context: (allow-none): a #GstGLContext to share OpenGL objects with
1023 * @error: (allow-none): a #GError
1025 * Creates an OpenGL context with the specified @other_context as a context
1026 * to share shareable OpenGL objects with. See the OpenGL specification for
1027 * what is shared between OpenGL contexts.
1029 * Since 1.20, the configuration can be overriden with the environment variable
1030 * `GST_GL_CONFIG` which is a stringified #GstStructure as would be returned
1031 * from gst_gl_context_get_config(). If `GST_GL_CONFIG` is not set, then the
1032 * config will be chosen from @other_context by calling
1033 * gst_gl_context_get_config() on @other_context. Otherwise, a default
1034 * configuration is used.
1036 * Calling gst_gl_context_request_config()) before calling
1037 * gst_gl_context_create() will override the config from @other_context but
1038 * will not override the `GST_GL_CONFIG` environment variable.
1040 * If an error occurs, and @error is not %NULL, then @error will contain
1041 * details of the error and %FALSE will be returned.
1043 * Should only be called once.
1045 * Returns: whether the context could successfully be created
1050 gst_gl_context_create (GstGLContext * context,
1051 GstGLContext * other_context, GError ** error)
1053 gboolean alive = FALSE;
1055 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1056 g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
1058 GST_DEBUG_OBJECT (context, " other_context:%" GST_PTR_FORMAT, other_context);
1060 _ensure_window (context);
1062 g_mutex_lock (&context->priv->render_lock);
1064 if (!context->priv->created) {
1065 g_weak_ref_set (&context->priv->other_context_ref, other_context);
1066 context->priv->error = error;
1067 if (other_context == NULL)
1068 context->priv->sharegroup = _context_share_group_new ();
1070 context->priv->sharegroup =
1071 _context_share_group_ref (other_context->priv->sharegroup);
1073 context->priv->gl_thread = g_thread_new ("gstglcontext",
1074 (GThreadFunc) gst_gl_context_create_thread, context);
1076 while (!context->priv->created)
1077 g_cond_wait (&context->priv->create_cond, &context->priv->render_lock);
1079 GST_INFO_OBJECT (context, "gl thread created");
1082 alive = context->priv->alive;
1084 g_mutex_unlock (&context->priv->render_lock);
1090 _create_context_info (GstGLContext * context, GstGLAPI gl_api, gint * gl_major,
1091 gint * gl_minor, GError ** error)
1093 const GstGLFuncs *gl;
1094 guint maj = 0, min = 0;
1095 GLenum gl_err = GL_NO_ERROR;
1096 const gchar *opengl_version = NULL;
1098 gl = context->gl_vtable;
1100 if (!gl->GetString || !gl->GetString (GL_VERSION)) {
1101 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1102 "glGetString not defined or returned invalid value");
1106 if (!gl->GetString (GL_SHADING_LANGUAGE_VERSION)) {
1107 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1108 "No GL shader support available");
1112 GST_INFO_OBJECT (context, "GL_VERSION: %s",
1113 GST_STR_NULL ((const gchar *) gl->GetString (GL_VERSION)));
1114 GST_INFO_OBJECT (context, "GL_SHADING_LANGUAGE_VERSION: %s",
1115 GST_STR_NULL ((const gchar *)
1116 gl->GetString (GL_SHADING_LANGUAGE_VERSION)));
1117 GST_INFO_OBJECT (context, "GL_VENDOR: %s",
1118 GST_STR_NULL ((const gchar *) gl->GetString (GL_VENDOR)));
1119 GST_INFO_OBJECT (context, "GL_RENDERER: %s",
1120 GST_STR_NULL ((const gchar *) gl->GetString (GL_RENDERER)));
1122 gl_err = gl->GetError ();
1123 if (gl_err != GL_NO_ERROR) {
1124 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1125 "glGetString error: 0x%x", gl_err);
1129 opengl_version = (const gchar *) gl->GetString (GL_VERSION);
1130 if (opengl_version && g_str_has_prefix (opengl_version, "OpenGL ES "))
1131 opengl_version = &opengl_version[10];
1134 sscanf (opengl_version, "%d.%d", &maj, &min);
1136 /* OpenGL > 1.2.0 */
1137 if (gl_api & GST_GL_API_OPENGL || gl_api & GST_GL_API_OPENGL3) {
1138 if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
1139 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS,
1140 "OpenGL >= 1.2.0 required, found %u.%u", maj, min);
1154 _compiled_api (void)
1156 GstGLAPI ret = GST_GL_API_NONE;
1158 #if GST_GL_HAVE_OPENGL
1159 ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
1161 #if GST_GL_HAVE_GLES2
1162 ret |= GST_GL_API_GLES2;
1169 _unlock_create_thread (GstGLContext * context)
1171 context->priv->created = TRUE;
1172 GST_INFO_OBJECT (context, "gl thread running");
1173 g_cond_signal (&context->priv->create_cond);
1174 g_mutex_unlock (&context->priv->render_lock);
1178 _build_extension_string (GstGLContext * context)
1180 const GstGLFuncs *gl = context->gl_vtable;
1181 GString *ext_g_str = g_string_sized_new (1024);
1182 const gchar *ext_const_c_str = NULL;
1186 gl->GetIntegerv (GL_NUM_EXTENSIONS, &n);
1188 for (i = 0; i < n; i++) {
1189 ext_const_c_str = (const gchar *) gl->GetStringi (GL_EXTENSIONS, i);
1190 if (ext_const_c_str)
1191 g_string_append_printf (ext_g_str, "%s ", ext_const_c_str);
1198 //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error)
1200 gst_gl_context_create_thread (GstGLContext * context)
1202 GstGLContextClass *context_class;
1203 GstGLWindowClass *window_class;
1204 GstGLAPI compiled_api, user_api, gl_api, display_api;
1206 gchar *compiled_api_s;
1208 gchar *display_api_s;
1209 const gchar *user_choice;
1211 GstGLContext *other_context;
1212 GstStructure *config;
1214 g_mutex_lock (&context->priv->render_lock);
1216 GST_DEBUG_OBJECT (context, "Creating thread");
1218 error = context->priv->error;
1219 other_context = g_weak_ref_get (&context->priv->other_context_ref);
1221 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1222 window_class = GST_GL_WINDOW_GET_CLASS (context->window);
1224 display_api = gst_gl_display_get_gl_api_unlocked (context->display);
1225 if (display_api == GST_GL_API_NONE) {
1226 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1227 "Cannot create context with satisfying requested apis "
1228 "(display has no GL api!)");
1232 if (window_class->open) {
1233 if (!window_class->open (context->window, error)) {
1234 GST_WARNING_OBJECT (context, "Failed to open window");
1235 g_assert (error == NULL || *error != NULL);
1240 compiled_api = _compiled_api ();
1241 compiled_api_s = gst_gl_api_to_string (compiled_api);
1243 user_choice = g_getenv ("GST_GL_API");
1244 user_api = gst_gl_api_from_string (user_choice);
1245 user_api_s = gst_gl_api_to_string (user_api);
1247 display_api_s = gst_gl_api_to_string (display_api);
1249 if ((user_api & compiled_api & display_api) == GST_GL_API_NONE) {
1250 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1251 "Cannot create context with the user requested api (%s). "
1252 "We have support for (%s), display api (%s)", user_api_s,
1253 compiled_api_s, display_api_s);
1254 g_free (user_api_s);
1255 g_free (compiled_api_s);
1256 g_free (display_api_s);
1261 const gchar *config_str = g_getenv ("GST_GL_CONFIG");
1263 GstStructure *config = gst_structure_from_string (config_str, NULL);
1265 g_set_error (error, GST_GL_CONTEXT_ERROR,
1266 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1267 "could not construct OpenGL config from the \'GST_GL_CONFIG\' "
1268 "environment variable");
1269 g_free (compiled_api_s);
1270 g_free (user_api_s);
1271 g_free (display_api_s);
1274 if (!gst_gl_context_request_config (context, gst_structure_copy (config))) {
1275 GST_WARNING_OBJECT (context,
1276 "failed to request config %" GST_PTR_FORMAT, config);
1278 GST_INFO_OBJECT (context, "requesting config from environment %"
1279 GST_PTR_FORMAT, config);
1281 gst_structure_free (config);
1282 } else if (other_context && !context->priv->requested_config) {
1283 GstStructure *config = gst_gl_context_get_config (other_context);
1285 if (!gst_gl_context_request_config (context,
1286 gst_structure_copy (config))) {
1287 GST_WARNING_OBJECT (context,
1288 "failed to request config %" GST_PTR_FORMAT, config);
1290 GST_INFO_OBJECT (context, "requesting config from other context %"
1291 GST_PTR_FORMAT " %" GST_PTR_FORMAT, other_context, config);
1293 gst_structure_free (config);
1298 if (context_class->choose_format &&
1299 !context_class->choose_format (context, error)) {
1300 GST_WARNING_OBJECT (context, "Failed to choose format");
1301 g_assert (error == NULL || *error != NULL);
1302 g_free (compiled_api_s);
1303 g_free (user_api_s);
1304 g_free (display_api_s);
1308 GST_INFO_OBJECT (context,
1309 "Attempting to create opengl context. user chosen api(s) (%s), "
1310 "compiled api support (%s) display api (%s)", user_api_s, compiled_api_s,
1313 if (!context_class->create_context (context,
1314 compiled_api & user_api & display_api, other_context, error)) {
1315 GST_WARNING_OBJECT (context, "Failed to create context");
1316 g_assert (error == NULL || *error != NULL);
1317 g_free (compiled_api_s);
1318 g_free (user_api_s);
1319 g_free (display_api_s);
1322 GST_INFO_OBJECT (context, "created context");
1324 if (!gst_gl_context_activate (context, TRUE)) {
1325 g_set_error (error, GST_GL_CONTEXT_ERROR,
1326 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
1327 "Failed to activate the GL Context");
1328 g_free (compiled_api_s);
1329 g_free (user_api_s);
1330 g_free (display_api_s);
1334 gl_api = gst_gl_context_get_gl_api (context);
1335 g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY);
1337 api_string = gst_gl_api_to_string (gl_api);
1338 GST_INFO_OBJECT (context, "available GL APIs: %s", api_string);
1340 if ((config = gst_gl_context_get_config (context))) {
1341 GST_DEBUG_OBJECT (context, "Chosen config %" GST_PTR_FORMAT, config);
1342 gst_structure_free (config);
1345 if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) {
1346 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1347 "failed to create context, context "
1348 "could not provide correct api. user (%s), compiled (%s), context (%s)",
1349 user_api_s, compiled_api_s, api_string);
1350 g_free (api_string);
1351 g_free (compiled_api_s);
1352 g_free (user_api_s);
1353 g_free (display_api_s);
1357 g_free (api_string);
1358 g_free (compiled_api_s);
1359 g_free (user_api_s);
1360 g_free (display_api_s);
1362 GST_DEBUG_OBJECT (context, "Filling info");
1363 if (!gst_gl_context_fill_info (context, error)) {
1364 g_assert (error == NULL || *error != NULL);
1368 context->priv->alive = TRUE;
1370 #if !defined(GST_DISABLE_GST_DEBUG)
1371 _gst_gl_debug_enable (context);
1374 if (other_context) {
1375 GST_DEBUG_OBJECT (context, "Unreffing other_context %" GST_PTR_FORMAT,
1377 gst_object_unref (other_context);
1380 /* unlocking of the render_lock happens when the
1381 * context's loop is running from inside that loop */
1382 gst_gl_window_send_message_async (context->window,
1383 (GstGLWindowCB) _unlock_create_thread, context, NULL);
1385 gst_gl_window_run (context->window);
1387 GST_INFO_OBJECT (context, "loop exited");
1389 g_mutex_lock (&context->priv->render_lock);
1390 context->priv->alive = FALSE;
1392 gst_gl_context_activate (context, FALSE);
1394 context_class->destroy_context (context);
1396 /* User supplied callback */
1397 if (context->window->close)
1398 context->window->close (context->window->close_data);
1400 /* window specific shutdown */
1401 if (window_class->close) {
1402 window_class->close (context->window);
1405 context->priv->created = FALSE;
1406 g_cond_signal (&context->priv->destroy_cond);
1407 g_mutex_unlock (&context->priv->render_lock);
1414 gst_object_unref (other_context);
1416 /* A context that fails to be created is considered created but not alive
1417 * and will never be able to be alive as creation can't happen */
1418 context->priv->created = TRUE;
1419 g_cond_signal (&context->priv->create_cond);
1420 g_mutex_unlock (&context->priv->render_lock);
1426 * gst_gl_context_destroy:
1427 * @context: a #GstGLContext:
1429 * Destroys an OpenGL context.
1431 * Should only be called after gst_gl_context_create() has been successfully
1432 * called for this context.
1437 gst_gl_context_destroy (GstGLContext * context)
1439 GstGLContextClass *context_class;
1441 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1442 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1443 g_return_if_fail (context_class->destroy_context != NULL);
1445 context_class->destroy_context (context);
1449 * gst_gl_context_fill_info:
1450 * @context: a #GstGLContext:
1451 * @error: (allow-none): a #GError to fill on failure
1453 * Fills @context's info (version, extensions, vtable, etc) from the GL
1454 * context in the current thread. Typically used with wrapped contexts to
1455 * allow wrapped contexts to be used as regular #GstGLContext's.
1460 gst_gl_context_fill_info (GstGLContext * context, GError ** error)
1463 GString *ext_g_str = NULL;
1464 const gchar *ext_const_c_str = NULL;
1468 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1469 g_return_val_if_fail (context->priv->active_thread == g_thread_self (),
1472 gl = context->gl_vtable;
1473 gl_api = gst_gl_context_get_gl_api (context);
1475 gl->GetError = gst_gl_context_get_proc_address (context, "glGetError");
1476 gl->GetString = gst_gl_context_get_proc_address (context, "glGetString");
1477 gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi");
1478 gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv");
1480 if (!gl->GetError || !gl->GetString) {
1481 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1482 "could not GetProcAddress core opengl functions");
1486 /* gl api specific code */
1487 ret = _create_context_info (context, gl_api, &context->priv->gl_major,
1488 &context->priv->gl_minor, error);
1491 g_assert (error == NULL || *error != NULL);
1495 /* GL core contexts and GLES3 */
1496 if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3)
1497 ext_g_str = _build_extension_string (context);
1499 if (ext_g_str && ext_g_str->len) {
1500 GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str);
1501 _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1502 context->priv->gl_minor, ext_g_str->str);
1504 context->priv->gl_exts = g_string_free (ext_g_str, FALSE);
1506 ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS);
1507 if (!ext_const_c_str)
1508 ext_const_c_str = "";
1510 GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str);
1511 _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1512 context->priv->gl_minor, ext_const_c_str);
1514 context->priv->gl_exts = g_strdup (ext_const_c_str);
1517 if (gl_api & GST_GL_API_OPENGL3
1518 && !gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 4, 1)
1519 && !gst_gl_check_extension ("GL_ARB_ES2_compatibility",
1520 context->priv->gl_exts)) {
1521 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1522 "An opengl3 context created but the required ES2 compatibility was not found");
1526 gst_gl_context_apply_quirks (context);
1528 if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
1530 #if GST_GL_HAVE_PLATFORM_GLX
1531 if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_GLX
1532 && !gst_gl_context_glx_fill_info (context, error))
1535 #if GST_GL_HAVE_PLATFORM_EGL
1536 if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_EGL
1537 && !gst_gl_context_egl_fill_info (context, error))
1549 * gst_gl_context_get_gl_context:
1550 * @context: a #GstGLContext:
1552 * Gets the backing OpenGL context used by @context.
1554 * Returns: The platform specific backing OpenGL context
1559 gst_gl_context_get_gl_context (GstGLContext * context)
1561 GstGLContextClass *context_class;
1564 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1565 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1566 g_return_val_if_fail (context_class->get_gl_context != NULL, 0);
1568 result = context_class->get_gl_context (context);
1574 * gst_gl_context_get_gl_platform:
1575 * @context: a #GstGLContext:
1577 * Gets the OpenGL platform that used by @context.
1579 * Returns: The platform specific backing OpenGL context
1584 gst_gl_context_get_gl_platform (GstGLContext * context)
1586 GstGLContextClass *context_class;
1588 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1589 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1590 g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
1592 return context_class->get_gl_platform (context);
1596 * gst_gl_context_get_display:
1597 * @context: a #GstGLContext:
1599 * Returns: (transfer full): the #GstGLDisplay associated with this @context
1604 gst_gl_context_get_display (GstGLContext * context)
1606 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1608 return gst_object_ref (context->display);
1613 GstGLContext *context;
1614 GstGLContextThreadFunc func;
1619 _gst_gl_context_thread_run_generic (RunGenericData * data)
1621 GST_TRACE_OBJECT (data->context, "running function:%p data:%p", data->func,
1624 data->func (data->context, data->data);
1628 * gst_gl_context_thread_add:
1629 * @context: a #GstGLContext
1630 * @func: (scope call): a #GstGLContextThreadFunc
1631 * @data: (closure): user data to call @func with
1633 * Execute @func in the OpenGL thread of @context with @data
1640 gst_gl_context_thread_add (GstGLContext * context,
1641 GstGLContextThreadFunc func, gpointer data)
1643 GstGLWindow *window;
1644 RunGenericData rdata;
1646 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1647 g_return_if_fail (func != NULL);
1649 if (GST_IS_GL_WRAPPED_CONTEXT (context))
1650 g_return_if_fail (context->priv->active_thread == g_thread_self ());
1652 if (context->priv->active_thread == g_thread_self ()) {
1653 func (context, data);
1657 rdata.context = context;
1661 window = gst_gl_context_get_window (context);
1663 gst_gl_window_send_message (window,
1664 GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata);
1666 gst_object_unref (window);
1670 * gst_gl_context_get_gl_version:
1671 * @context: a #GstGLContext
1672 * @maj: (out): resulting major version
1673 * @min: (out): resulting minor version
1675 * Returns the OpenGL version implemented by @context. See
1676 * gst_gl_context_get_gl_api() for retrieving the OpenGL api implemented by
1682 gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min)
1684 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1685 g_return_if_fail (!(maj == NULL && min == NULL));
1688 *maj = context->priv->gl_major;
1691 *min = context->priv->gl_minor;
1695 * gst_gl_context_check_gl_version:
1696 * @context: a #GstGLContext
1697 * @api: api type required
1698 * @maj: major version required
1699 * @min: minor version required
1701 * Returns: whether OpenGL context implements the required api and specified
1707 gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api,
1710 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1712 if (maj > context->priv->gl_major)
1715 if ((gst_gl_context_get_gl_api (context) & api) == GST_GL_API_NONE)
1718 if (maj < context->priv->gl_major)
1721 if (min > context->priv->gl_minor)
1728 * gst_gl_context_check_feature:
1729 * @context: a #GstGLContext
1730 * @feature: a platform specific feature
1732 * Check for an OpenGL @feature being supported.
1734 * Note: Most features require that the context be created before it is
1735 * possible to determine their existence and so will fail if that is not the
1738 * Returns: Whether @feature is supported by @context
1743 gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
1745 GstGLContextClass *context_class;
1747 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1748 g_return_val_if_fail (feature != NULL, FALSE);
1750 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1752 if (g_strstr_len (feature, 3, "GL_"))
1753 return gst_gl_check_extension (feature, context->priv->gl_exts);
1755 if (!context_class->check_feature)
1758 return context_class->check_feature (context, feature);
1762 * gst_gl_context_get_current:
1764 * See also gst_gl_context_activate().
1766 * Returns: (transfer none) (nullable): the #GstGLContext active in the current thread or %NULL
1771 gst_gl_context_get_current (void)
1773 return g_private_get (¤t_context_key);
1777 * gst_gl_context_is_shared:
1778 * @context: a #GstGLContext
1780 * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
1785 gst_gl_context_is_shared (GstGLContext * context)
1787 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1789 if (!context->priv->sharegroup)
1792 if (GST_IS_GL_WRAPPED_CONTEXT (context))
1793 g_return_val_if_fail (context->priv->active_thread, FALSE);
1795 g_return_val_if_fail (context->priv->alive, FALSE);
1797 return _context_share_group_is_shared (context->priv->sharegroup);
1801 * gst_gl_context_set_shared_with:
1802 * @context: a wrapped #GstGLContext
1803 * @share: another #GstGLContext
1805 * Will internally set @context as shared with @share
1810 gst_gl_context_set_shared_with (GstGLContext * context, GstGLContext * share)
1812 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1813 g_return_if_fail (GST_IS_GL_CONTEXT (share));
1814 g_return_if_fail (!gst_gl_context_is_shared (context));
1815 /* XXX: may be a little too strict */
1816 g_return_if_fail (GST_IS_GL_WRAPPED_CONTEXT (context));
1818 if (context->priv->sharegroup)
1819 _context_share_group_unref (context->priv->sharegroup);
1820 context->priv->sharegroup =
1821 _context_share_group_ref (share->priv->sharegroup);
1825 gst_gl_context_default_get_gl_platform_version (GstGLContext * context,
1826 gint * major, gint * minor)
1835 * gst_gl_context_get_gl_platform_version:
1836 * @context: a #GstGLContext
1837 * @major: (out): return for the major version
1838 * @minor: (out): return for the minor version
1840 * Get the version of the OpenGL platform (GLX, EGL, etc) used. Only valid
1841 * after a call to gst_gl_context_create().
1844 gst_gl_context_get_gl_platform_version (GstGLContext * context, gint * major,
1847 GstGLContextClass *context_class;
1849 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1850 g_return_if_fail (major != NULL);
1851 g_return_if_fail (minor != NULL);
1852 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1853 g_return_if_fail (context_class->get_gl_platform_version != NULL);
1855 context_class->get_gl_platform_version (context, major, minor);
1859 * gst_gl_context_swap_buffers:
1860 * @context: a #GstGLContext
1862 * Swap the front and back buffers on the window attached to @context.
1863 * This will display the frame on the next refresh cycle.
1866 gst_gl_context_swap_buffers (GstGLContext * context)
1868 GstGLContextClass *context_class;
1870 g_return_if_fail (GST_IS_GL_CONTEXT (context));
1871 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1872 g_return_if_fail (context_class->swap_buffers != NULL);
1874 context_class->swap_buffers (context);
1878 * gst_gl_context_get_config:
1879 * @context: the #GstGLContext
1881 * Retrieve the OpenGL configuration for this context. The context must
1882 * have been successfully created for this function to return a valid value.
1884 * Not all implementations currently support retrieving the config and will
1885 * return %NULL when not supported.
1887 * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context.
1892 gst_gl_context_get_config (GstGLContext * context)
1894 GstGLContextClass *context_class;
1896 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1897 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1898 if (!context_class->get_config) {
1899 GST_FIXME_OBJECT (context, "does not support retrieving a config");
1903 return context_class->get_config (context);
1907 * gst_gl_context_request_config:
1908 * @context: the #GstGLContext
1909 * @gl_config: (nullable) (transfer full): a configuration structure for
1910 * configuring the OpenGL context
1912 * Set the OpenGL configuration for this context. The context must not
1913 * have been created for this function to succeed. Setting a %NULL
1914 * @config has the affect of removing any specific configuration request.
1916 * Not all implementations currently support retrieving the config and this
1917 * function will return FALSE when not supported.
1919 * Note that calling this function may cause a subsequent
1920 * gst_gl_context_create() to fail if @config could not be matched with
1921 * the platform-specific configuration.
1923 * Note that the actual config used may be differ from the requested values.
1925 * Returns: whether @gl_config could be successfully set on @context
1930 gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config)
1932 GstGLContextClass *context_class;
1935 g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1936 g_return_val_if_fail (context->priv->created == FALSE, FALSE);
1937 context_class = GST_GL_CONTEXT_GET_CLASS (context);
1938 if (!context_class->request_config) {
1939 gst_structure_free (gl_config);
1940 GST_FIXME_OBJECT (context, "does not support requesting a config");
1944 ret = context_class->request_config (context, gst_structure_copy (gl_config));
1946 if (context->priv->requested_config)
1947 gst_structure_free (context->priv->requested_config);
1948 context->priv->requested_config = gl_config;
1950 gst_structure_free (gl_config);
1957 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
1959 GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1961 return context_wrap->available_apis;
1965 gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
1967 GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1969 return context_wrap->handle;
1972 static GstGLPlatform
1973 gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
1975 GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1977 return context_wrap->platform;
1981 gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
1984 GThread *old_thread = context->priv->gl_thread;
1985 context->priv->gl_thread = g_thread_ref (g_thread_self ());
1987 g_thread_unref (old_thread);
1990 if (context->priv->gl_thread) {
1991 g_thread_unref (context->priv->gl_thread);
1992 context->priv->gl_thread = NULL;
2000 _structure_copy_if_set (gpointer data, gpointer user_data)
2002 GstStructure *ret = NULL;
2005 ret = gst_structure_copy (data);
2009 static GstStructure *
2010 gst_gl_wrapped_context_get_config (GstGLContext * context)
2014 ret = g_object_dup_data (G_OBJECT (context),
2015 GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME,
2016 (GDuplicateFunc) _structure_copy_if_set, NULL);
2018 GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT,
2022 GST_FIXME_OBJECT (context, "wrapped context could not retrieve config. "
2023 "The application may be missing a call to gst_gl_context_fill_info() "
2024 "or the specific platform implemention is not implemented for "
2025 "retrieving the config from a wrapped OpenGL context.");
2031 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
2033 GstGLContextClass *context_class = (GstGLContextClass *) klass;
2035 context_class->get_gl_context =
2036 GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
2037 context_class->get_gl_api =
2038 GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
2039 context_class->get_gl_platform =
2040 GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
2041 context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
2042 context_class->get_config =
2043 GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_config);
2047 gst_gl_wrapped_context_init (GstGLWrappedContext * context)
2051 G_GNUC_INTERNAL gboolean
2052 _gst_gl_context_debug_is_enabled (GstGLContext * context)
2054 #if !defined(GST_DISABLE_GST_DEBUG)
2055 GstDebugLevel level;
2057 level = gst_debug_category_get_threshold (gst_gl_debug);
2059 if (level < GST_LEVEL_WARNING) {
2060 GST_CAT_INFO_OBJECT (gst_gl_context_debug, context, "Disabling GL context "
2061 "debugging (gldebug category debug level < warning)");