3056a4ab5ac12204602ebbd69f9f68e4b155a29d
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / gst-libs / gst / gl / gstglcontext.c
1 /*
2  * GStreamer
3  * Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 /**
22  * SECTION:gstglcontext
23  * @short_description: OpenGL context abstraction
24  * @title: GstGLContext
25  * @see_also: #GstGLDisplay, #GstGLWindow
26  *
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.
30  *
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
45  *                    functionality.
46  */
47
48 #ifdef HAVE_CONFIG_H
49 # include "config.h"
50 #endif
51
52 #if defined(ANDROID) || defined(__ANDROID__)
53 /* Avoid a linker error with _isoc99_sscanf() when building a shared library
54  * for android
55  */
56 #define _GNU_SOURCE
57 #endif
58
59 #include "gstglcontext.h"
60 #include <gst/gl/gl.h>
61
62 #include <gmodule.h>
63 #include <string.h>
64 #include <stdio.h>
65
66 #include "gstglcontext_private.h"
67 #include "gstglfeature.h"
68 #include "gstglfeature_private.h"
69 #include "gstglfuncs.h"
70
71 #ifndef GL_NUM_EXTENSIONS
72 #define GL_NUM_EXTENSIONS 0x0000821d
73 #endif
74
75 #if GST_GL_HAVE_PLATFORM_GLX
76 #include "x11/gstglcontext_glx.h"
77 #endif
78 #if GST_GL_HAVE_PLATFORM_EGL
79 #include "egl/gstglcontext_egl.h"
80 #endif
81 #if GST_GL_HAVE_PLATFORM_CGL
82 #include "cocoa/gstglcontext_cocoa.h"
83 #endif
84 #if GST_GL_HAVE_PLATFORM_WGL
85 #include "wgl/gstglcontext_wgl.h"
86 #endif
87 #if GST_GL_HAVE_PLATFORM_EAGL
88 #include "eagl/gstglcontext_eagl.h"
89 #endif
90
91 extern void _gst_gl_debug_enable (GstGLContext * context);
92
93 static GPrivate current_context_key;
94
95 static GModule *module_self;
96 static GOnce module_self_gonce = G_ONCE_INIT;
97
98 #if GST_GL_HAVE_OPENGL
99 static GOnce module_opengl_gonce = G_ONCE_INIT;
100 static GModule *module_opengl;
101
102 static gpointer
103 load_opengl_module (gpointer user_data)
104 {
105 #ifdef GST_GL_LIBGL_MODULE_NAME
106   module_opengl = g_module_open (GST_GL_LIBGL_MODULE_NAME, G_MODULE_BIND_LAZY);
107 #else
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);
114
115   /* This automatically handles the suffix and even .la files */
116   if (!module_opengl)
117     module_opengl = g_module_open ("libGL", G_MODULE_BIND_LAZY);
118 #endif
119
120   return NULL;
121 }
122 #endif
123
124 #if GST_GL_HAVE_GLES2
125 static GOnce module_gles2_gonce = G_ONCE_INIT;
126 static GModule *module_gles2;
127
128 static gpointer
129 load_gles2_module (gpointer user_data)
130 {
131 #ifdef GST_GL_LIBGLESV2_MODULE_NAME
132   module_gles2 =
133       g_module_open (GST_GL_LIBGLESV2_MODULE_NAME, G_MODULE_BIND_LAZY);
134 #else
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);
139
140   /* This automatically handles the suffix and even .la files */
141   if (!module_gles2)
142     module_gles2 = g_module_open ("libGLESv2", G_MODULE_BIND_LAZY);
143
144 #endif
145
146   return NULL;
147 }
148 #endif
149
150 static gpointer
151 load_self_module (gpointer user_data)
152 {
153   module_self = g_module_open (NULL, G_MODULE_BIND_LAZY);
154
155   return NULL;
156 }
157
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.
162  *
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.
165  *
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.
168  */
169 struct ContextShareGroup
170 {
171   int refcount;
172 };
173
174 static struct ContextShareGroup *
175 _context_share_group_new (void)
176 {
177   struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1);
178
179   ret->refcount = 1;
180
181   return ret;
182 }
183
184 static struct ContextShareGroup *
185 _context_share_group_ref (struct ContextShareGroup *share)
186 {
187   g_atomic_int_inc (&share->refcount);
188   return share;
189 }
190
191 static void
192 _context_share_group_unref (struct ContextShareGroup *share)
193 {
194   if (g_atomic_int_dec_and_test (&share->refcount))
195     g_free (share);
196 }
197
198 static gboolean
199 _context_share_group_is_shared (struct ContextShareGroup *share)
200 {
201   return g_atomic_int_get (&share->refcount) > 1;
202 }
203
204 #define GST_CAT_DEFAULT gst_gl_context_debug
205 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
206 GST_DEBUG_CATEGORY_STATIC (gst_gl_debug);
207
208 static void _init_debug (void);
209
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);
214
215 struct _GstGLContextPrivate
216 {
217   GThread *gl_thread;
218   GThread *active_thread;
219
220   /* conditions */
221   GMutex render_lock;
222   GCond create_cond;
223   GCond destroy_cond;
224
225   gboolean created;
226   gboolean alive;
227
228   GWeakRef other_context_ref;
229   struct ContextShareGroup *sharegroup;
230   GError **error;
231
232   gint gl_major;
233   gint gl_minor;
234
235   gchar *gl_exts;
236   GstStructure *requested_config;
237 };
238
239 typedef struct
240 {
241   GstGLContext parent;
242
243   guintptr handle;
244   GstGLPlatform platform;
245   GstGLAPI available_apis;
246 } GstGLWrappedContext;
247
248 typedef struct
249 {
250   GstGLContextClass parent;
251 } GstGLWrappedContextClass;
252
253 #define gst_gl_context_parent_class parent_class
254 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLContext, gst_gl_context,
255     GST_TYPE_OBJECT);
256
257 G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
258     GST_TYPE_GL_CONTEXT);
259
260 /**
261  * gst_gl_context_error_quark:
262  *
263  * Returns: the quark used for #GstGLContext in #GError's
264  */
265 GQuark
266 gst_gl_context_error_quark (void)
267 {
268   return g_quark_from_static_string ("gst-gl-context-error-quark");
269 }
270
271 static void
272 _ensure_window (GstGLContext * context)
273 {
274   GstGLWindow *window;
275
276   if (context->window)
277     return;
278
279   window = gst_gl_display_create_window (context->display);
280
281   gst_gl_context_set_window (context, window);
282
283   gst_object_unref (window);
284 }
285
286 static void
287 gst_gl_context_init (GstGLContext * context)
288 {
289   context->priv = gst_gl_context_get_instance_private (context);
290
291   context->window = NULL;
292   context->gl_vtable = g_slice_alloc0 (sizeof (GstGLFuncs));
293
294   g_mutex_init (&context->priv->render_lock);
295
296   g_cond_init (&context->priv->create_cond);
297   g_cond_init (&context->priv->destroy_cond);
298   context->priv->created = FALSE;
299
300   g_weak_ref_init (&context->priv->other_context_ref, NULL);
301 }
302
303 static void
304 gst_gl_context_class_init (GstGLContextClass * klass)
305 {
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);
310
311   G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize;
312
313   _init_debug ();
314 }
315
316 static void
317 _init_debug (void)
318 {
319   static gsize _init = 0;
320
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);
326   }
327 }
328
329 /**
330  * gst_gl_context_new:
331  * @display: a #GstGLDisplay
332  *
333  * Create a new #GstGLContext with the specified @display
334  *
335  * Returns: a new #GstGLContext
336  *
337  * Since: 1.4
338  */
339 GstGLContext *
340 gst_gl_context_new (GstGLDisplay * display)
341 {
342   GstGLContext *context = NULL;
343   const gchar *user_choice;
344
345   _init_debug ();
346
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));
353 #endif
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));
357 #endif
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));
361 #endif
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));
365 #endif
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));
369 #endif
370
371   if (!context) {
372     /* subclass returned a NULL context */
373     GST_WARNING ("Could not create context. user specified %s",
374         user_choice ? user_choice : "(null)");
375
376     return NULL;
377   }
378
379   context->display = gst_object_ref (display);
380
381   GST_DEBUG_OBJECT (context,
382       "Done creating context for display %" GST_PTR_FORMAT " (user_choice:%s)",
383       display, user_choice);
384
385   return context;
386 }
387
388 /**
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
394  *
395  * Wraps an existing OpenGL context into a #GstGLContext.
396  *
397  * Note: The caller is responsible for ensuring that the OpenGL context
398  * represented by @handle stays alive while the returned #GstGLContext is
399  * active.
400  *
401  * @context_type must not be %GST_GL_PLATFORM_NONE or %GST_GL_PLATFORM_ANY
402  *
403  * @available_apis must not be %GST_GL_API_NONE or %GST_GL_API_ANY
404  *
405  * Returns: (transfer full) (nullable): a #GstGLContext wrapping @handle
406  *
407  * Since: 1.4
408  */
409 GstGLContext *
410 gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
411     GstGLPlatform context_type, GstGLAPI available_apis)
412 {
413   GstGLContext *context;
414   GstGLWrappedContext *context_wrap = NULL;
415   GstGLContextClass *context_class;
416   GstGLAPI display_api;
417
418   _init_debug ();
419
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);
426
427   display_api = gst_gl_display_get_gl_api (display);
428   g_return_val_if_fail ((display_api & available_apis) != GST_GL_API_NONE,
429       NULL);
430
431   context_wrap = g_object_new (GST_TYPE_GL_WRAPPED_CONTEXT, NULL);
432   gst_object_ref_sink (context_wrap);
433
434   context = (GstGLContext *) context_wrap;
435
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;
441
442   context_class = GST_GL_CONTEXT_GET_CLASS (context);
443
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;
448   }
449 #endif
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;
454   }
455 #endif
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;
461   }
462 #endif
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;
467   }
468 #endif
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;
474   }
475 #endif
476
477   if (!context_class->get_current_context) {
478     /* we don't have API support */
479     gst_object_unref (context);
480     return NULL;
481   }
482
483   return context;
484 }
485
486 /**
487  * gst_gl_context_get_current_gl_context:
488  * @context_type: a #GstGLPlatform specifying the type of context to retrieve
489  *
490  * Returns: (nullable): The OpenGL context handle current in the calling thread or %NULL
491  *
492  * Since: 1.6
493  */
494 guintptr
495 gst_gl_context_get_current_gl_context (GstGLPlatform context_type)
496 {
497   guintptr handle = 0;
498
499   _init_debug ();
500
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 ();
504 #endif
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 ();
508 #endif
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 ();
512 #endif
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 ();
516 #endif
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 ();
520 #endif
521
522   if (!handle)
523     GST_WARNING ("Could not retrieve current context");
524
525   return handle;
526 }
527
528 /**
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
533  *
534  * Attempts to use the @context_type specific GetProcAddress implementations
535  * to retrieve @name.
536  *
537  * See also gst_gl_context_get_proc_address().
538  *
539  * Returns: (nullable): a function pointer for @name, or %NULL
540  *
541  * Since: 1.6
542  */
543 gpointer
544 gst_gl_context_get_proc_address_with_platform (GstGLPlatform context_type,
545     GstGLAPI gl_api, const gchar * name)
546 {
547   gpointer ret = NULL;
548
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);
552 #endif
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);
556 #endif
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);
560 #endif
561   /* CGL and EAGL rely on the default impl */
562
563   if (!ret)
564     ret = gst_gl_context_default_get_proc_address (gl_api, name);
565
566   return ret;
567 }
568
569 /**
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
574  *
575  * If an error occurs, @major and @minor are not modified and %GST_GL_API_NONE is
576  * returned.
577  *
578  * Returns: The version supported by the OpenGL context current in the calling
579  *          thread or %GST_GL_API_NONE
580  *
581  * Since: 1.6
582  */
583 GstGLAPI
584 gst_gl_context_get_current_gl_api (GstGLPlatform platform, guint * major,
585     guint * minor)
586 {
587   const GLubyte *(GSTGLAPI * GetString) (GLenum name);
588 #if GST_GL_HAVE_OPENGL
589   void (GSTGLAPI * GetIntegerv) (GLenum name, GLuint * n);
590 #endif
591   const gchar *version;
592   gint maj, min, n;
593   GstGLAPI ret = (1U << 31);
594
595   _init_debug ();
596
597   while (ret != GST_GL_API_NONE) {
598     /* FIXME: attempt to delve into the platform specific GetProcAddress */
599     GetString =
600         gst_gl_context_get_proc_address_with_platform (platform, ret,
601         "glGetString");
602 #if GST_GL_HAVE_OPENGL
603     GetIntegerv =
604         gst_gl_context_get_proc_address_with_platform (platform, ret,
605         "glGetIntegerv");
606 #endif
607     if (!GetString) {
608       goto next;
609     }
610
611     version = (const gchar *) GetString (GL_VERSION);
612     if (!version)
613       goto next;
614
615     /* strlen (x.x) == 3 */
616     n = strlen (version);
617     if (n < 3)
618       goto next;
619
620     if (g_strstr_len (version, 9, "OpenGL ES")) {
621       /* strlen (OpenGL ES x.x) == 13 */
622       if (n < 13)
623         goto next;
624
625       sscanf (&version[10], "%d.%d", &maj, &min);
626
627       if (maj <= 0 || min < 0)
628         goto next;
629
630       if (maj == 1) {
631         ret = GST_GL_API_GLES1;
632         break;
633       } else if (maj == 2 || maj == 3) {
634         ret = GST_GL_API_GLES2;
635         break;
636       }
637
638       goto next;
639     } else {
640       sscanf (version, "%d.%d", &maj, &min);
641
642       if (maj <= 0 || min < 0)
643         goto next;
644
645 #if GST_GL_HAVE_OPENGL
646       if (GetIntegerv && (maj > 3 || (maj == 3 && min > 1))) {
647         GLuint context_flags = 0;
648
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;
655         break;
656       }
657 #endif
658       ret = GST_GL_API_OPENGL;
659       break;
660     }
661
662   next:
663     /* iterate through the apis */
664     ret >>= 1;
665   }
666
667   if (ret == GST_GL_API_NONE)
668     return GST_GL_API_NONE;
669
670   if (major)
671     *major = maj;
672   if (minor)
673     *minor = min;
674
675   return ret;
676 }
677
678 static void
679 gst_gl_context_finalize (GObject * object)
680 {
681   GstGLContext *context = GST_GL_CONTEXT (object);
682
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);
686
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);
691
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");
696
697       if (context->priv->gl_thread) {
698         g_thread_unref (context->priv->gl_thread);
699         context->priv->gl_thread = NULL;
700       }
701     }
702     g_mutex_unlock (&context->priv->render_lock);
703
704     gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
705     gst_object_unref (context->window);
706     context->window = NULL;
707   }
708
709   if (context->priv->active_thread) {
710     g_thread_unref (context->priv->active_thread);
711     context->priv->active_thread = NULL;
712   }
713
714   if (context->priv->gl_thread) {
715     g_thread_unref (context->priv->gl_thread);
716     context->priv->gl_thread = NULL;
717   }
718
719   if (context->priv->sharegroup) {
720     _context_share_group_unref (context->priv->sharegroup);
721     context->priv->sharegroup = NULL;
722   }
723
724   if (context->display) {
725     gst_object_unref (context->display);
726     context->display = NULL;
727   }
728
729   if (context->gl_vtable) {
730     g_slice_free (GstGLFuncs, context->gl_vtable);
731     context->gl_vtable = NULL;
732   }
733
734   if (context->priv->requested_config)
735     gst_structure_free (context->priv->requested_config);
736   context->priv->requested_config = NULL;
737
738   g_mutex_clear (&context->priv->render_lock);
739
740   g_cond_clear (&context->priv->create_cond);
741   g_cond_clear (&context->priv->destroy_cond);
742
743   g_free (context->priv->gl_exts);
744   g_weak_ref_clear (&context->priv->other_context_ref);
745
746   GST_DEBUG_OBJECT (context, "End of finalize");
747   G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object);
748 }
749
750 /**
751  * gst_gl_context_activate:
752  * @context: a #GstGLContext
753  * @activate: %TRUE to activate, %FALSE to deactivate
754  *
755  * (De)activate the OpenGL context represented by this @context.
756  *
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.
759  *
760  * Returns: Whether the activation succeeded
761  *
762  * Since: 1.4
763  */
764 gboolean
765 gst_gl_context_activate (GstGLContext * context, gboolean activate)
766 {
767   GstGLContextClass *context_class;
768   gboolean result;
769
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);
773
774   GST_DEBUG_OBJECT (context, "activate:%d", activate);
775
776   GST_OBJECT_LOCK (context);
777   result = context_class->activate (context, activate);
778
779   if (result && activate) {
780     GThread *old_thread = context->priv->active_thread;
781     context->priv->active_thread = g_thread_ref (g_thread_self ());
782     if (old_thread) {
783       g_thread_unref (old_thread);
784     }
785
786     g_private_set (&current_context_key, context);
787   } else {
788     if (context->priv->active_thread) {
789       g_thread_unref (context->priv->active_thread);
790       context->priv->active_thread = NULL;
791     }
792     g_private_set (&current_context_key, NULL);
793   }
794   GST_OBJECT_UNLOCK (context);
795
796   return result;
797 }
798
799 /**
800  * gst_gl_context_get_thread:
801  * @context: a #GstGLContext
802  *
803  * Returns: (transfer full) (nullable): The #GThread, @context is current in or NULL
804  *
805  * Since: 1.6
806  */
807 GThread *
808 gst_gl_context_get_thread (GstGLContext * context)
809 {
810   GThread *ret;
811
812   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
813
814   GST_OBJECT_LOCK (context);
815   ret = context->priv->active_thread;
816   if (ret)
817     g_thread_ref (ret);
818   GST_OBJECT_UNLOCK (context);
819
820   return ret;
821 }
822
823 /**
824  * gst_gl_context_get_gl_api:
825  * @context: a #GstGLContext
826  *
827  * Get the currently enabled OpenGL api.
828  *
829  * The currently available API may be limited by the #GstGLDisplay in use and/or
830  * the #GstGLWindow chosen.
831  *
832  * Returns: the available OpenGL api
833  *
834  * Since: 1.4
835  */
836 GstGLAPI
837 gst_gl_context_get_gl_api (GstGLContext * context)
838 {
839   GstGLContextClass *context_class;
840
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);
844
845   return context_class->get_gl_api (context);
846 }
847
848 /**
849  * gst_gl_context_get_proc_address:
850  * @context: a #GstGLContext
851  * @name: an opengl function name
852  *
853  * Get a function pointer to a specified opengl function, @name.  If the the
854  * specific function does not exist, NULL is returned instead.
855  *
856  * Platform specific functions (names starting 'egl', 'glX', 'wgl', etc) can also
857  * be retrieved using this method.
858  *
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.
863  *
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.
867  * e.g.
868  *
869  * |[<!-- language="C" -->
870  * void (GSTGLAPI *PFN_glGetIntegerv) (GLenum name, GLint * ret)
871  * ]|
872  *
873  * Returns: (nullable): a function pointer or %NULL
874  *
875  * Since: 1.4
876  */
877 gpointer
878 gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
879 {
880   gpointer ret;
881   GstGLContextClass *context_class;
882   GstGLAPI gl_api;
883
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);
887
888   gl_api = gst_gl_context_get_gl_api (context);
889   ret = context_class->get_proc_address (gl_api, name);
890
891   return ret;
892 }
893
894 /**
895  * gst_gl_context_default_get_proc_address:
896  * @gl_api: a #GstGLAPI
897  * @name: then function to get the address of
898  *
899  * A default implementation of the various GetProcAddress functions that looks
900  * for @name in the OpenGL shared libraries or in the current process.
901  *
902  * See also: gst_gl_context_get_proc_address()
903  *
904  * Returns: (nullable): an address pointing to @name or %NULL
905  *
906  * Since: 1.4
907  */
908 gpointer
909 gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar * name)
910 {
911   gpointer ret = NULL;
912
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);
917     if (module_gles2)
918       g_module_symbol (module_gles2, name, &ret);
919   }
920 #endif
921
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);
925     if (module_opengl)
926       g_module_symbol (module_opengl, name, &ret);
927   }
928 #endif
929
930   /* Otherwise fall back to the current module */
931   g_once (&module_self_gonce, load_self_module, NULL);
932   if (!ret)
933     g_module_symbol (module_self, name, &ret);
934
935   return ret;
936 }
937
938 /**
939  * gst_gl_context_set_window:
940  * @context: a #GstGLContext
941  * @window: (transfer full): a #GstGLWindow
942  *
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
945  * already running.
946  *
947  * Returns: Whether the window was successfully updated
948  *
949  * Since: 1.4
950  */
951 gboolean
952 gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
953 {
954   g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
955
956   GST_DEBUG_OBJECT (context, "window:%" GST_PTR_FORMAT, window);
957
958   /* we can't change the window while we are running */
959   if (context->priv->alive)
960     return FALSE;
961
962   if (window)
963     g_weak_ref_set (&window->context_ref, context);
964
965   if (context->window)
966     gst_object_unref (context->window);
967
968   context->window = window ? gst_object_ref (window) : NULL;
969
970   return TRUE;
971 }
972
973 /**
974  * gst_gl_context_get_window:
975  * @context: a #GstGLContext
976  *
977  * Returns: (transfer full) (nullable): the currently set window
978  *
979  * Since: 1.4
980  */
981 GstGLWindow *
982 gst_gl_context_get_window (GstGLContext * context)
983 {
984   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
985
986   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
987     GST_WARNING_OBJECT (context, "context is not toplevel, returning NULL");
988     return NULL;
989   }
990
991   _ensure_window (context);
992
993   return gst_object_ref (context->window);
994 }
995
996 /**
997  * gst_gl_context_can_share:
998  * @context: a #GstGLContext
999  * @other_context: another #GstGLContext
1000  *
1001  * Note: This will always fail for two wrapped #GstGLContext's
1002  *
1003  * Returns: whether @context and @other_context are able to share OpenGL
1004  *      resources.
1005  *
1006  * Since: 1.6
1007  */
1008 gboolean
1009 gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
1010 {
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);
1013
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;
1017 }
1018
1019 /**
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
1024  *
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.
1028  *
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.
1035  *
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.
1039  *
1040  * If an error occurs, and @error is not %NULL, then @error will contain
1041  * details of the error and %FALSE will be returned.
1042  *
1043  * Should only be called once.
1044  *
1045  * Returns: whether the context could successfully be created
1046  *
1047  * Since: 1.4
1048  */
1049 gboolean
1050 gst_gl_context_create (GstGLContext * context,
1051     GstGLContext * other_context, GError ** error)
1052 {
1053   gboolean alive = FALSE;
1054
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);
1057
1058   GST_DEBUG_OBJECT (context, " other_context:%" GST_PTR_FORMAT, other_context);
1059
1060   _ensure_window (context);
1061
1062   g_mutex_lock (&context->priv->render_lock);
1063
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 ();
1069     else
1070       context->priv->sharegroup =
1071           _context_share_group_ref (other_context->priv->sharegroup);
1072
1073     context->priv->gl_thread = g_thread_new ("gstglcontext",
1074         (GThreadFunc) gst_gl_context_create_thread, context);
1075
1076     while (!context->priv->created)
1077       g_cond_wait (&context->priv->create_cond, &context->priv->render_lock);
1078
1079     GST_INFO_OBJECT (context, "gl thread created");
1080   }
1081
1082   alive = context->priv->alive;
1083
1084   g_mutex_unlock (&context->priv->render_lock);
1085
1086   return alive;
1087 }
1088
1089 static gboolean
1090 _create_context_info (GstGLContext * context, GstGLAPI gl_api, gint * gl_major,
1091     gint * gl_minor, GError ** error)
1092 {
1093   const GstGLFuncs *gl;
1094   guint maj = 0, min = 0;
1095   GLenum gl_err = GL_NO_ERROR;
1096   const gchar *opengl_version = NULL;
1097
1098   gl = context->gl_vtable;
1099
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");
1103     return FALSE;
1104   }
1105
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");
1109     return FALSE;
1110   }
1111
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)));
1121
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);
1126     return FALSE;
1127   }
1128
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];
1132
1133   if (opengl_version)
1134     sscanf (opengl_version, "%d.%d", &maj, &min);
1135
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);
1141       return FALSE;
1142     }
1143   }
1144
1145   if (gl_major)
1146     *gl_major = maj;
1147   if (gl_minor)
1148     *gl_minor = min;
1149
1150   return TRUE;
1151 }
1152
1153 static GstGLAPI
1154 _compiled_api (void)
1155 {
1156   GstGLAPI ret = GST_GL_API_NONE;
1157
1158 #if GST_GL_HAVE_OPENGL
1159   ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
1160 #endif
1161 #if GST_GL_HAVE_GLES2
1162   ret |= GST_GL_API_GLES2;
1163 #endif
1164
1165   return ret;
1166 }
1167
1168 static void
1169 _unlock_create_thread (GstGLContext * context)
1170 {
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);
1175 }
1176
1177 static GString *
1178 _build_extension_string (GstGLContext * context)
1179 {
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;
1183   GLint i = 0;
1184   GLint n = 0;
1185
1186   gl->GetIntegerv (GL_NUM_EXTENSIONS, &n);
1187
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);
1192   }
1193
1194   return ext_g_str;
1195 }
1196
1197 //gboolean
1198 //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error)
1199 static gpointer
1200 gst_gl_context_create_thread (GstGLContext * context)
1201 {
1202   GstGLContextClass *context_class;
1203   GstGLWindowClass *window_class;
1204   GstGLAPI compiled_api, user_api, gl_api, display_api;
1205   gchar *api_string;
1206   gchar *compiled_api_s;
1207   gchar *user_api_s;
1208   gchar *display_api_s;
1209   const gchar *user_choice;
1210   GError **error;
1211   GstGLContext *other_context;
1212   GstStructure *config;
1213
1214   g_mutex_lock (&context->priv->render_lock);
1215
1216   GST_DEBUG_OBJECT (context, "Creating thread");
1217
1218   error = context->priv->error;
1219   other_context = g_weak_ref_get (&context->priv->other_context_ref);
1220
1221   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1222   window_class = GST_GL_WINDOW_GET_CLASS (context->window);
1223
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!)");
1229     goto failure;
1230   }
1231
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);
1236       goto failure;
1237     }
1238   }
1239
1240   compiled_api = _compiled_api ();
1241   compiled_api_s = gst_gl_api_to_string (compiled_api);
1242
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);
1246
1247   display_api_s = gst_gl_api_to_string (display_api);
1248
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);
1257     goto failure;
1258   }
1259
1260   {
1261     const gchar *config_str = g_getenv ("GST_GL_CONFIG");
1262     if (config_str) {
1263       GstStructure *config = gst_structure_from_string (config_str, NULL);
1264       if (!config) {
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);
1272         goto failure;
1273       }
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);
1277       } else {
1278         GST_INFO_OBJECT (context, "requesting config from environment %"
1279             GST_PTR_FORMAT, config);
1280       }
1281       gst_structure_free (config);
1282     } else if (other_context && !context->priv->requested_config) {
1283       GstStructure *config = gst_gl_context_get_config (other_context);
1284       if (config) {
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);
1289         } else {
1290           GST_INFO_OBJECT (context, "requesting config from other context %"
1291               GST_PTR_FORMAT " %" GST_PTR_FORMAT, other_context, config);
1292         }
1293         gst_structure_free (config);
1294       }
1295     }
1296   }
1297
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);
1305     goto failure;
1306   }
1307
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,
1311       display_api_s);
1312
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);
1320     goto failure;
1321   }
1322   GST_INFO_OBJECT (context, "created context");
1323
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);
1331     goto failure;
1332   }
1333
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);
1336
1337   api_string = gst_gl_api_to_string (gl_api);
1338   GST_INFO_OBJECT (context, "available GL APIs: %s", api_string);
1339
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);
1343   }
1344
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);
1354     goto failure;
1355   }
1356
1357   g_free (api_string);
1358   g_free (compiled_api_s);
1359   g_free (user_api_s);
1360   g_free (display_api_s);
1361
1362   GST_DEBUG_OBJECT (context, "Filling info");
1363   if (!gst_gl_context_fill_info (context, error)) {
1364     g_assert (error == NULL || *error != NULL);
1365     goto failure;
1366   }
1367
1368   context->priv->alive = TRUE;
1369
1370 #if !defined(GST_DISABLE_GST_DEBUG)
1371   _gst_gl_debug_enable (context);
1372 #endif
1373
1374   if (other_context) {
1375     GST_DEBUG_OBJECT (context, "Unreffing other_context %" GST_PTR_FORMAT,
1376         other_context);
1377     gst_object_unref (other_context);
1378   }
1379
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);
1384
1385   gst_gl_window_run (context->window);
1386
1387   GST_INFO_OBJECT (context, "loop exited");
1388
1389   g_mutex_lock (&context->priv->render_lock);
1390   context->priv->alive = FALSE;
1391
1392   gst_gl_context_activate (context, FALSE);
1393
1394   context_class->destroy_context (context);
1395
1396   /* User supplied callback */
1397   if (context->window->close)
1398     context->window->close (context->window->close_data);
1399
1400   /* window specific shutdown */
1401   if (window_class->close) {
1402     window_class->close (context->window);
1403   }
1404
1405   context->priv->created = FALSE;
1406   g_cond_signal (&context->priv->destroy_cond);
1407   g_mutex_unlock (&context->priv->render_lock);
1408
1409   return NULL;
1410
1411 failure:
1412   {
1413     if (other_context)
1414       gst_object_unref (other_context);
1415
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);
1421     return NULL;
1422   }
1423 }
1424
1425 /**
1426  * gst_gl_context_destroy:
1427  * @context: a #GstGLContext:
1428  *
1429  * Destroys an OpenGL context.
1430  *
1431  * Should only be called after gst_gl_context_create() has been successfully
1432  * called for this context.
1433  *
1434  * Since: 1.6
1435  */
1436 void
1437 gst_gl_context_destroy (GstGLContext * context)
1438 {
1439   GstGLContextClass *context_class;
1440
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);
1444
1445   context_class->destroy_context (context);
1446 }
1447
1448 /**
1449  * gst_gl_context_fill_info:
1450  * @context: a #GstGLContext:
1451  * @error: (allow-none): a #GError to fill on failure
1452  *
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.
1456  *
1457  * Since: 1.6
1458  */
1459 gboolean
1460 gst_gl_context_fill_info (GstGLContext * context, GError ** error)
1461 {
1462   GstGLFuncs *gl;
1463   GString *ext_g_str = NULL;
1464   const gchar *ext_const_c_str = NULL;
1465   GstGLAPI gl_api;
1466   gboolean ret;
1467
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 (),
1470       FALSE);
1471
1472   gl = context->gl_vtable;
1473   gl_api = gst_gl_context_get_gl_api (context);
1474
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");
1479
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");
1483     goto failure;
1484   }
1485
1486   /* gl api specific code */
1487   ret = _create_context_info (context, gl_api, &context->priv->gl_major,
1488       &context->priv->gl_minor, error);
1489
1490   if (!ret) {
1491     g_assert (error == NULL || *error != NULL);
1492     goto failure;
1493   }
1494
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);
1498
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);
1503
1504     context->priv->gl_exts = g_string_free (ext_g_str, FALSE);
1505   } else {
1506     ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS);
1507     if (!ext_const_c_str)
1508       ext_const_c_str = "";
1509
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);
1513
1514     context->priv->gl_exts = g_strdup (ext_const_c_str);
1515   }
1516
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");
1523     goto failure;
1524   }
1525
1526   gst_gl_context_apply_quirks (context);
1527
1528   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
1529     /* XXX: vfunc? */
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))
1533       goto failure;
1534 #endif
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))
1538       goto failure;
1539 #endif
1540   }
1541
1542   return TRUE;
1543
1544 failure:
1545   return FALSE;
1546 }
1547
1548 /**
1549  * gst_gl_context_get_gl_context:
1550  * @context: a #GstGLContext:
1551  *
1552  * Gets the backing OpenGL context used by @context.
1553  *
1554  * Returns: The platform specific backing OpenGL context
1555  *
1556  * Since: 1.4
1557  */
1558 guintptr
1559 gst_gl_context_get_gl_context (GstGLContext * context)
1560 {
1561   GstGLContextClass *context_class;
1562   guintptr result;
1563
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);
1567
1568   result = context_class->get_gl_context (context);
1569
1570   return result;
1571 }
1572
1573 /**
1574  * gst_gl_context_get_gl_platform:
1575  * @context: a #GstGLContext:
1576  *
1577  * Gets the OpenGL platform that used by @context.
1578  *
1579  * Returns: The platform specific backing OpenGL context
1580  *
1581  * Since: 1.4
1582  */
1583 GstGLPlatform
1584 gst_gl_context_get_gl_platform (GstGLContext * context)
1585 {
1586   GstGLContextClass *context_class;
1587
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);
1591
1592   return context_class->get_gl_platform (context);
1593 }
1594
1595 /**
1596  * gst_gl_context_get_display:
1597  * @context: a #GstGLContext:
1598  *
1599  * Returns: (transfer full): the #GstGLDisplay associated with this @context
1600  *
1601  * Since: 1.4
1602  */
1603 GstGLDisplay *
1604 gst_gl_context_get_display (GstGLContext * context)
1605 {
1606   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1607
1608   return gst_object_ref (context->display);
1609 }
1610
1611 typedef struct
1612 {
1613   GstGLContext *context;
1614   GstGLContextThreadFunc func;
1615   gpointer data;
1616 } RunGenericData;
1617
1618 static void
1619 _gst_gl_context_thread_run_generic (RunGenericData * data)
1620 {
1621   GST_TRACE_OBJECT (data->context, "running function:%p data:%p", data->func,
1622       data->data);
1623
1624   data->func (data->context, data->data);
1625 }
1626
1627 /**
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
1632  *
1633  * Execute @func in the OpenGL thread of @context with @data
1634  *
1635  * MT-safe
1636  *
1637  * Since: 1.4
1638  */
1639 void
1640 gst_gl_context_thread_add (GstGLContext * context,
1641     GstGLContextThreadFunc func, gpointer data)
1642 {
1643   GstGLWindow *window;
1644   RunGenericData rdata;
1645
1646   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1647   g_return_if_fail (func != NULL);
1648
1649   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1650     g_return_if_fail (context->priv->active_thread == g_thread_self ());
1651
1652   if (context->priv->active_thread == g_thread_self ()) {
1653     func (context, data);
1654     return;
1655   }
1656
1657   rdata.context = context;
1658   rdata.data = data;
1659   rdata.func = func;
1660
1661   window = gst_gl_context_get_window (context);
1662
1663   gst_gl_window_send_message (window,
1664       GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata);
1665
1666   gst_object_unref (window);
1667 }
1668
1669 /**
1670  * gst_gl_context_get_gl_version:
1671  * @context: a #GstGLContext
1672  * @maj: (out): resulting major version
1673  * @min: (out): resulting minor version
1674  *
1675  * Returns the OpenGL version implemented by @context.  See
1676  * gst_gl_context_get_gl_api() for retrieving the OpenGL api implemented by
1677  * @context.
1678  *
1679  * Since: 1.4
1680  */
1681 void
1682 gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min)
1683 {
1684   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1685   g_return_if_fail (!(maj == NULL && min == NULL));
1686
1687   if (maj)
1688     *maj = context->priv->gl_major;
1689
1690   if (min)
1691     *min = context->priv->gl_minor;
1692 }
1693
1694 /**
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
1700  *
1701  * Returns: whether OpenGL context implements the required api and specified
1702  * version.
1703  *
1704  * Since: 1.4
1705  */
1706 gboolean
1707 gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api,
1708     gint maj, gint min)
1709 {
1710   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1711
1712   if (maj > context->priv->gl_major)
1713     return FALSE;
1714
1715   if ((gst_gl_context_get_gl_api (context) & api) == GST_GL_API_NONE)
1716     return FALSE;
1717
1718   if (maj < context->priv->gl_major)
1719     return TRUE;
1720
1721   if (min > context->priv->gl_minor)
1722     return FALSE;
1723
1724   return TRUE;
1725 }
1726
1727 /**
1728  * gst_gl_context_check_feature:
1729  * @context: a #GstGLContext
1730  * @feature: a platform specific feature
1731  *
1732  * Check for an OpenGL @feature being supported.
1733  *
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
1736  * case.
1737  *
1738  * Returns: Whether @feature is supported by @context
1739  *
1740  * Since: 1.4
1741  */
1742 gboolean
1743 gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
1744 {
1745   GstGLContextClass *context_class;
1746
1747   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1748   g_return_val_if_fail (feature != NULL, FALSE);
1749
1750   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1751
1752   if (g_strstr_len (feature, 3, "GL_"))
1753     return gst_gl_check_extension (feature, context->priv->gl_exts);
1754
1755   if (!context_class->check_feature)
1756     return FALSE;
1757
1758   return context_class->check_feature (context, feature);
1759 }
1760
1761 /**
1762  * gst_gl_context_get_current:
1763  *
1764  * See also gst_gl_context_activate().
1765  *
1766  * Returns: (transfer none) (nullable): the #GstGLContext active in the current thread or %NULL
1767  *
1768  * Since: 1.6
1769  */
1770 GstGLContext *
1771 gst_gl_context_get_current (void)
1772 {
1773   return g_private_get (&current_context_key);
1774 }
1775
1776 /**
1777  * gst_gl_context_is_shared:
1778  * @context: a #GstGLContext
1779  *
1780  * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
1781  *
1782  * Since: 1.8
1783  */
1784 gboolean
1785 gst_gl_context_is_shared (GstGLContext * context)
1786 {
1787   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1788
1789   if (!context->priv->sharegroup)
1790     return FALSE;
1791
1792   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1793     g_return_val_if_fail (context->priv->active_thread, FALSE);
1794   else
1795     g_return_val_if_fail (context->priv->alive, FALSE);
1796
1797   return _context_share_group_is_shared (context->priv->sharegroup);
1798 }
1799
1800 /**
1801  * gst_gl_context_set_shared_with:
1802  * @context: a wrapped #GstGLContext
1803  * @share: another #GstGLContext
1804  *
1805  * Will internally set @context as shared with @share
1806  *
1807  * Since: 1.8
1808  */
1809 void
1810 gst_gl_context_set_shared_with (GstGLContext * context, GstGLContext * share)
1811 {
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));
1817
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);
1822 }
1823
1824 static void
1825 gst_gl_context_default_get_gl_platform_version (GstGLContext * context,
1826     gint * major, gint * minor)
1827 {
1828   if (major)
1829     *major = 0;
1830   if (minor)
1831     *minor = 0;
1832 }
1833
1834 /**
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
1839  *
1840  * Get the version of the OpenGL platform (GLX, EGL, etc) used.  Only valid
1841  * after a call to gst_gl_context_create().
1842  */
1843 void
1844 gst_gl_context_get_gl_platform_version (GstGLContext * context, gint * major,
1845     gint * minor)
1846 {
1847   GstGLContextClass *context_class;
1848
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);
1854
1855   context_class->get_gl_platform_version (context, major, minor);
1856 }
1857
1858 /**
1859  * gst_gl_context_swap_buffers:
1860  * @context: a #GstGLContext
1861  *
1862  * Swap the front and back buffers on the window attached to @context.
1863  * This will display the frame on the next refresh cycle.
1864  */
1865 void
1866 gst_gl_context_swap_buffers (GstGLContext * context)
1867 {
1868   GstGLContextClass *context_class;
1869
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);
1873
1874   context_class->swap_buffers (context);
1875 }
1876
1877 /**
1878  * gst_gl_context_get_config:
1879  * @context: the #GstGLContext
1880  *
1881  * Retrieve the OpenGL configuration for this context.  The context must
1882  * have been successfully created for this function to return a valid value.
1883  *
1884  * Not all implementations currently support retrieving the config and will
1885  * return %NULL when not supported.
1886  *
1887  * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context.
1888  *
1889  * Since: 1.20
1890  */
1891 GstStructure *
1892 gst_gl_context_get_config (GstGLContext * context)
1893 {
1894   GstGLContextClass *context_class;
1895
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");
1900     return NULL;
1901   }
1902
1903   return context_class->get_config (context);
1904 }
1905
1906 /**
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
1911  *
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.
1915  *
1916  * Not all implementations currently support retrieving the config and this
1917  * function will return FALSE when not supported.
1918  *
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.
1922  *
1923  * Note that the actual config used may be differ from the requested values.
1924  *
1925  * Returns: whether @gl_config could be successfully set on @context
1926  *
1927  * Since: 1.20
1928  */
1929 gboolean
1930 gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config)
1931 {
1932   GstGLContextClass *context_class;
1933   gboolean ret;
1934
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");
1941     return FALSE;
1942   }
1943
1944   ret = context_class->request_config (context, gst_structure_copy (gl_config));
1945   if (ret) {
1946     if (context->priv->requested_config)
1947       gst_structure_free (context->priv->requested_config);
1948     context->priv->requested_config = gl_config;
1949   } else {
1950     gst_structure_free (gl_config);
1951   }
1952
1953   return ret;
1954 }
1955
1956 static GstGLAPI
1957 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
1958 {
1959   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1960
1961   return context_wrap->available_apis;
1962 }
1963
1964 static guintptr
1965 gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
1966 {
1967   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1968
1969   return context_wrap->handle;
1970 }
1971
1972 static GstGLPlatform
1973 gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
1974 {
1975   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1976
1977   return context_wrap->platform;
1978 }
1979
1980 static gboolean
1981 gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
1982 {
1983   if (activate) {
1984     GThread *old_thread = context->priv->gl_thread;
1985     context->priv->gl_thread = g_thread_ref (g_thread_self ());
1986     if (old_thread) {
1987       g_thread_unref (old_thread);
1988     }
1989   } else {
1990     if (context->priv->gl_thread) {
1991       g_thread_unref (context->priv->gl_thread);
1992       context->priv->gl_thread = NULL;
1993     }
1994   }
1995
1996   return TRUE;
1997 }
1998
1999 static gpointer
2000 _structure_copy_if_set (gpointer data, gpointer user_data)
2001 {
2002   GstStructure *ret = NULL;
2003
2004   if (data)
2005     ret = gst_structure_copy (data);
2006   return ret;
2007 }
2008
2009 static GstStructure *
2010 gst_gl_wrapped_context_get_config (GstGLContext * context)
2011 {
2012   GstStructure *ret;
2013
2014   ret = g_object_dup_data (G_OBJECT (context),
2015       GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME,
2016       (GDuplicateFunc) _structure_copy_if_set, NULL);
2017   if (ret) {
2018     GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT,
2019         ret);
2020     return ret;
2021   } else {
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.");
2026     return NULL;
2027   }
2028 }
2029
2030 static void
2031 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
2032 {
2033   GstGLContextClass *context_class = (GstGLContextClass *) klass;
2034
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);
2044 }
2045
2046 static void
2047 gst_gl_wrapped_context_init (GstGLWrappedContext * context)
2048 {
2049 }
2050
2051 G_GNUC_INTERNAL gboolean
2052 _gst_gl_context_debug_is_enabled (GstGLContext * context)
2053 {
2054 #if !defined(GST_DISABLE_GST_DEBUG)
2055   GstDebugLevel level;
2056
2057   level = gst_debug_category_get_threshold (gst_gl_debug);
2058
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)");
2062     return FALSE;
2063   }
2064   return TRUE;
2065 #else
2066   return FALSE;
2067 #endif
2068 }