a0b1f06a694211b2787502320cd29b9185c75c92
[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): 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   if (!context_wrap) {
435     /* subclass returned a NULL context */
436     GST_ERROR ("Could not wrap existing context");
437
438     return NULL;
439   }
440
441   context = (GstGLContext *) context_wrap;
442
443   context->display = gst_object_ref (display);
444   context->priv->sharegroup = _context_share_group_new ();
445   context_wrap->handle = handle;
446   context_wrap->platform = context_type;
447   context_wrap->available_apis = available_apis;
448
449   context_class = GST_GL_CONTEXT_GET_CLASS (context);
450
451 #if GST_GL_HAVE_PLATFORM_GLX
452   if (context_type == GST_GL_PLATFORM_GLX) {
453     context_class->get_current_context = gst_gl_context_glx_get_current_context;
454     context_class->get_proc_address = gst_gl_context_glx_get_proc_address;
455   }
456 #endif
457 #if GST_GL_HAVE_PLATFORM_EGL
458   if (context_type == GST_GL_PLATFORM_EGL) {
459     context_class->get_current_context = gst_gl_context_egl_get_current_context;
460     context_class->get_proc_address = gst_gl_context_egl_get_proc_address;
461   }
462 #endif
463 #if GST_GL_HAVE_PLATFORM_CGL
464   if (context_type == GST_GL_PLATFORM_CGL) {
465     context_class->get_current_context =
466         gst_gl_context_cocoa_get_current_context;
467     context_class->get_proc_address = gst_gl_context_default_get_proc_address;
468   }
469 #endif
470 #if GST_GL_HAVE_PLATFORM_WGL
471   if (context_type == GST_GL_PLATFORM_WGL) {
472     context_class->get_current_context = gst_gl_context_wgl_get_current_context;
473     context_class->get_proc_address = gst_gl_context_wgl_get_proc_address;
474   }
475 #endif
476 #if GST_GL_HAVE_PLATFORM_EAGL
477   if (context_type == GST_GL_PLATFORM_EAGL) {
478     context_class->get_current_context =
479         gst_gl_context_eagl_get_current_context;
480     context_class->get_proc_address = gst_gl_context_default_get_proc_address;
481   }
482 #endif
483
484   if (!context_class->get_current_context) {
485     /* we don't have API support */
486     gst_object_unref (context);
487     return NULL;
488   }
489
490   return context;
491 }
492
493 /**
494  * gst_gl_context_get_current_gl_context:
495  * @context_type: a #GstGLPlatform specifying the type of context to retrieve
496  *
497  * Returns: (nullable): The OpenGL context handle current in the calling thread or %NULL
498  *
499  * Since: 1.6
500  */
501 guintptr
502 gst_gl_context_get_current_gl_context (GstGLPlatform context_type)
503 {
504   guintptr handle = 0;
505
506   _init_debug ();
507
508 #if GST_GL_HAVE_PLATFORM_GLX
509   if (!handle && (context_type & GST_GL_PLATFORM_GLX) != 0)
510     handle = gst_gl_context_glx_get_current_context ();
511 #endif
512 #if GST_GL_HAVE_PLATFORM_EGL
513   if (!handle && (context_type & GST_GL_PLATFORM_EGL) != 0)
514     handle = gst_gl_context_egl_get_current_context ();
515 #endif
516 #if GST_GL_HAVE_PLATFORM_CGL
517   if (!handle && (context_type & GST_GL_PLATFORM_CGL) != 0)
518     handle = gst_gl_context_cocoa_get_current_context ();
519 #endif
520 #if GST_GL_HAVE_PLATFORM_WGL
521   if (!handle && (context_type & GST_GL_PLATFORM_WGL) != 0)
522     handle = gst_gl_context_wgl_get_current_context ();
523 #endif
524 #if GST_GL_HAVE_PLATFORM_EAGL
525   if (!handle && (context_type & GST_GL_PLATFORM_EAGL) != 0)
526     handle = gst_gl_context_eagl_get_current_context ();
527 #endif
528
529   if (!handle)
530     GST_WARNING ("Could not retrieve current context");
531
532   return handle;
533 }
534
535 /**
536  * gst_gl_context_get_proc_address_with_platform:
537  * @context_type: a #GstGLPlatform
538  * @gl_api: a #GstGLAPI
539  * @name: the name of the function to retrieve
540  *
541  * Attempts to use the @context_type specific GetProcAddress implementations
542  * to retrieve @name.
543  *
544  * See also gst_gl_context_get_proc_address().
545  *
546  * Returns: (nullable): a function pointer for @name, or %NULL
547  *
548  * Since: 1.6
549  */
550 gpointer
551 gst_gl_context_get_proc_address_with_platform (GstGLPlatform context_type,
552     GstGLAPI gl_api, const gchar * name)
553 {
554   gpointer ret = NULL;
555
556 #if GST_GL_HAVE_PLATFORM_GLX
557   if (!ret && (context_type & GST_GL_PLATFORM_GLX) != 0)
558     ret = gst_gl_context_glx_get_proc_address (gl_api, name);
559 #endif
560 #if GST_GL_HAVE_PLATFORM_EGL
561   if (!ret && (context_type & GST_GL_PLATFORM_EGL) != 0)
562     ret = gst_gl_context_egl_get_proc_address (gl_api, name);
563 #endif
564 #if GST_GL_HAVE_PLATFORM_WGL
565   if (!ret && (context_type & GST_GL_PLATFORM_WGL) != 0)
566     ret = gst_gl_context_wgl_get_proc_address (gl_api, name);
567 #endif
568   /* CGL and EAGL rely on the default impl */
569
570   if (!ret)
571     ret = gst_gl_context_default_get_proc_address (gl_api, name);
572
573   return ret;
574 }
575
576 /**
577  * gst_gl_context_get_current_gl_api:
578  * @platform: the #GstGLPlatform to retrieve the API for
579  * @major: (out) (allow-none): the major version
580  * @minor: (out) (allow-none): the minor version
581  *
582  * If an error occurs, @major and @minor are not modified and %GST_GL_API_NONE is
583  * returned.
584  *
585  * Returns: The version supported by the OpenGL context current in the calling
586  *          thread or %GST_GL_API_NONE
587  *
588  * Since: 1.6
589  */
590 GstGLAPI
591 gst_gl_context_get_current_gl_api (GstGLPlatform platform, guint * major,
592     guint * minor)
593 {
594   const GLubyte *(GSTGLAPI * GetString) (GLenum name);
595 #if GST_GL_HAVE_OPENGL
596   void (GSTGLAPI * GetIntegerv) (GLenum name, GLuint * n);
597 #endif
598   const gchar *version;
599   gint maj, min, n;
600   GstGLAPI ret = (1U << 31);
601
602   _init_debug ();
603
604   while (ret != GST_GL_API_NONE) {
605     /* FIXME: attempt to delve into the platform specific GetProcAddress */
606     GetString =
607         gst_gl_context_get_proc_address_with_platform (platform, ret,
608         "glGetString");
609 #if GST_GL_HAVE_OPENGL
610     GetIntegerv =
611         gst_gl_context_get_proc_address_with_platform (platform, ret,
612         "glGetIntegerv");
613 #endif
614     if (!GetString) {
615       goto next;
616     }
617
618     version = (const gchar *) GetString (GL_VERSION);
619     if (!version)
620       goto next;
621
622     /* strlen (x.x) == 3 */
623     n = strlen (version);
624     if (n < 3)
625       goto next;
626
627     if (g_strstr_len (version, 9, "OpenGL ES")) {
628       /* strlen (OpenGL ES x.x) == 13 */
629       if (n < 13)
630         goto next;
631
632       sscanf (&version[10], "%d.%d", &maj, &min);
633
634       if (maj <= 0 || min < 0)
635         goto next;
636
637       if (maj == 1) {
638         ret = GST_GL_API_GLES1;
639         break;
640       } else if (maj == 2 || maj == 3) {
641         ret = GST_GL_API_GLES2;
642         break;
643       }
644
645       goto next;
646     } else {
647       sscanf (version, "%d.%d", &maj, &min);
648
649       if (maj <= 0 || min < 0)
650         goto next;
651
652 #if GST_GL_HAVE_OPENGL
653       if (GetIntegerv && (maj > 3 || (maj == 3 && min > 1))) {
654         GLuint context_flags = 0;
655
656         ret = GST_GL_API_NONE;
657         GetIntegerv (GL_CONTEXT_PROFILE_MASK, &context_flags);
658         if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT)
659           ret |= GST_GL_API_OPENGL3;
660         if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
661           ret |= GST_GL_API_OPENGL;
662         break;
663       }
664 #endif
665       ret = GST_GL_API_OPENGL;
666       break;
667     }
668
669   next:
670     /* iterate through the apis */
671     ret >>= 1;
672   }
673
674   if (ret == GST_GL_API_NONE)
675     return GST_GL_API_NONE;
676
677   if (major)
678     *major = maj;
679   if (minor)
680     *minor = min;
681
682   return ret;
683 }
684
685 static void
686 gst_gl_context_finalize (GObject * object)
687 {
688   GstGLContext *context = GST_GL_CONTEXT (object);
689
690   if (context->window) {
691     gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
692     gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
693
694     g_mutex_lock (&context->priv->render_lock);
695     if (context->priv->alive) {
696       GST_INFO_OBJECT (context, "send quit gl window loop");
697       gst_gl_window_quit (context->window);
698
699       GST_INFO_OBJECT (context, "joining gl thread");
700       while (context->priv->alive)
701         g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
702       GST_INFO_OBJECT (context, "gl thread joined");
703
704       if (context->priv->gl_thread) {
705         g_thread_unref (context->priv->gl_thread);
706         context->priv->gl_thread = NULL;
707       }
708     }
709     g_mutex_unlock (&context->priv->render_lock);
710
711     gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
712     gst_object_unref (context->window);
713     context->window = NULL;
714   }
715
716   if (context->priv->active_thread) {
717     g_thread_unref (context->priv->active_thread);
718     context->priv->active_thread = NULL;
719   }
720
721   if (context->priv->gl_thread) {
722     g_thread_unref (context->priv->gl_thread);
723     context->priv->gl_thread = NULL;
724   }
725
726   if (context->priv->sharegroup) {
727     _context_share_group_unref (context->priv->sharegroup);
728     context->priv->sharegroup = NULL;
729   }
730
731   if (context->display) {
732     gst_object_unref (context->display);
733     context->display = NULL;
734   }
735
736   if (context->gl_vtable) {
737     g_slice_free (GstGLFuncs, context->gl_vtable);
738     context->gl_vtable = NULL;
739   }
740
741   if (context->priv->requested_config)
742     gst_structure_free (context->priv->requested_config);
743   context->priv->requested_config = NULL;
744
745   g_mutex_clear (&context->priv->render_lock);
746
747   g_cond_clear (&context->priv->create_cond);
748   g_cond_clear (&context->priv->destroy_cond);
749
750   g_free (context->priv->gl_exts);
751   g_weak_ref_clear (&context->priv->other_context_ref);
752
753   GST_DEBUG_OBJECT (context, "End of finalize");
754   G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object);
755 }
756
757 /**
758  * gst_gl_context_activate:
759  * @context: a #GstGLContext
760  * @activate: %TRUE to activate, %FALSE to deactivate
761  *
762  * (De)activate the OpenGL context represented by this @context.
763  *
764  * In OpenGL terms, calls eglMakeCurrent or similar with this context and the
765  * currently set window.  See gst_gl_context_set_window() for details.
766  *
767  * Returns: Whether the activation succeeded
768  *
769  * Since: 1.4
770  */
771 gboolean
772 gst_gl_context_activate (GstGLContext * context, gboolean activate)
773 {
774   GstGLContextClass *context_class;
775   gboolean result;
776
777   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
778   context_class = GST_GL_CONTEXT_GET_CLASS (context);
779   g_return_val_if_fail (context_class->activate != NULL, FALSE);
780
781   GST_DEBUG_OBJECT (context, "activate:%d", activate);
782
783   GST_OBJECT_LOCK (context);
784   result = context_class->activate (context, activate);
785
786   if (result && activate) {
787     GThread *old_thread = context->priv->active_thread;
788     context->priv->active_thread = g_thread_ref (g_thread_self ());
789     if (old_thread) {
790       g_thread_unref (old_thread);
791     }
792
793     g_private_set (&current_context_key, context);
794   } else {
795     if (context->priv->active_thread) {
796       g_thread_unref (context->priv->active_thread);
797       context->priv->active_thread = NULL;
798     }
799     g_private_set (&current_context_key, NULL);
800   }
801   GST_OBJECT_UNLOCK (context);
802
803   return result;
804 }
805
806 /**
807  * gst_gl_context_get_thread:
808  * @context: a #GstGLContext
809  *
810  * Returns: (transfer full) (nullable): The #GThread, @context is current in or NULL
811  *
812  * Since: 1.6
813  */
814 GThread *
815 gst_gl_context_get_thread (GstGLContext * context)
816 {
817   GThread *ret;
818
819   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
820
821   GST_OBJECT_LOCK (context);
822   ret = context->priv->active_thread;
823   if (ret)
824     g_thread_ref (ret);
825   GST_OBJECT_UNLOCK (context);
826
827   return ret;
828 }
829
830 /**
831  * gst_gl_context_get_gl_api:
832  * @context: a #GstGLContext
833  *
834  * Get the currently enabled OpenGL api.
835  *
836  * The currently available API may be limited by the #GstGLDisplay in use and/or
837  * the #GstGLWindow chosen.
838  *
839  * Returns: the available OpenGL api
840  *
841  * Since: 1.4
842  */
843 GstGLAPI
844 gst_gl_context_get_gl_api (GstGLContext * context)
845 {
846   GstGLContextClass *context_class;
847
848   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), GST_GL_API_NONE);
849   context_class = GST_GL_CONTEXT_GET_CLASS (context);
850   g_return_val_if_fail (context_class->get_gl_api != NULL, GST_GL_API_NONE);
851
852   return context_class->get_gl_api (context);
853 }
854
855 /**
856  * gst_gl_context_get_proc_address:
857  * @context: a #GstGLContext
858  * @name: an opengl function name
859  *
860  * Get a function pointer to a specified opengl function, @name.  If the the
861  * specific function does not exist, NULL is returned instead.
862  *
863  * Platform specific functions (names starting 'egl', 'glX', 'wgl', etc) can also
864  * be retrieved using this method.
865  *
866  * Note: This function may return valid function pointers that may not be valid
867  * to call in @context.  The caller is responsible for ensuring that the
868  * returned function is a valid function to call in @context by either checking
869  * the OpenGL API and version or for an appropriate OpenGL extension.
870  *
871  * Note: On success, you need to cast the returned function pointer to the
872  * correct type to be able to call it correctly.  On 32-bit Windows, this will
873  * include the `GSTGLAPI` identifier to use the correct calling convention.
874  * e.g.
875  *
876  * |[<!-- language="C" -->
877  * void (GSTGLAPI *PFN_glGetIntegerv) (GLenum name, GLint * ret)
878  * ]|
879  *
880  * Returns: (nullable): a function pointer or %NULL
881  *
882  * Since: 1.4
883  */
884 gpointer
885 gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
886 {
887   gpointer ret;
888   GstGLContextClass *context_class;
889   GstGLAPI gl_api;
890
891   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
892   context_class = GST_GL_CONTEXT_GET_CLASS (context);
893   g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);
894
895   gl_api = gst_gl_context_get_gl_api (context);
896   ret = context_class->get_proc_address (gl_api, name);
897
898   return ret;
899 }
900
901 /**
902  * gst_gl_context_default_get_proc_address:
903  * @gl_api: a #GstGLAPI
904  * @name: then function to get the address of
905  *
906  * A default implementation of the various GetProcAddress functions that looks
907  * for @name in the OpenGL shared libraries or in the current process.
908  *
909  * See also: gst_gl_context_get_proc_address()
910  *
911  * Returns: (nullable): an address pointing to @name or %NULL
912  *
913  * Since: 1.4
914  */
915 gpointer
916 gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar * name)
917 {
918   gpointer ret = NULL;
919
920   /* First try to load symbol from the selected GL API for this context */
921 #if GST_GL_HAVE_GLES2
922   if (!ret && (gl_api & GST_GL_API_GLES2)) {
923     g_once (&module_gles2_gonce, load_gles2_module, NULL);
924     if (module_gles2)
925       g_module_symbol (module_gles2, name, &ret);
926   }
927 #endif
928
929 #if GST_GL_HAVE_OPENGL
930   if (!ret && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
931     g_once (&module_opengl_gonce, load_opengl_module, NULL);
932     if (module_opengl)
933       g_module_symbol (module_opengl, name, &ret);
934   }
935 #endif
936
937   /* Otherwise fall back to the current module */
938   g_once (&module_self_gonce, load_self_module, NULL);
939   if (!ret)
940     g_module_symbol (module_self, name, &ret);
941
942   return ret;
943 }
944
945 /**
946  * gst_gl_context_set_window:
947  * @context: a #GstGLContext
948  * @window: (transfer full): a #GstGLWindow
949  *
950  * Set's the current window on @context to @window.  The window can only be
951  * changed before gst_gl_context_create() has been called and the @window is not
952  * already running.
953  *
954  * Returns: Whether the window was successfully updated
955  *
956  * Since: 1.4
957  */
958 gboolean
959 gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
960 {
961   g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
962
963   GST_DEBUG_OBJECT (context, "window:%" GST_PTR_FORMAT, window);
964
965   /* we can't change the window while we are running */
966   if (context->priv->alive)
967     return FALSE;
968
969   if (window)
970     g_weak_ref_set (&window->context_ref, context);
971
972   if (context->window)
973     gst_object_unref (context->window);
974
975   context->window = window ? gst_object_ref (window) : NULL;
976
977   return TRUE;
978 }
979
980 /**
981  * gst_gl_context_get_window:
982  * @context: a #GstGLContext
983  *
984  * Returns: (transfer full) (nullable): the currently set window
985  *
986  * Since: 1.4
987  */
988 GstGLWindow *
989 gst_gl_context_get_window (GstGLContext * context)
990 {
991   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
992
993   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
994     GST_WARNING_OBJECT (context, "context is not toplevel, returning NULL");
995     return NULL;
996   }
997
998   _ensure_window (context);
999
1000   return gst_object_ref (context->window);
1001 }
1002
1003 /**
1004  * gst_gl_context_can_share:
1005  * @context: a #GstGLContext
1006  * @other_context: another #GstGLContext
1007  *
1008  * Note: This will always fail for two wrapped #GstGLContext's
1009  *
1010  * Returns: whether @context and @other_context are able to share OpenGL
1011  *      resources.
1012  *
1013  * Since: 1.6
1014  */
1015 gboolean
1016 gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
1017 {
1018   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1019   g_return_val_if_fail (GST_IS_GL_CONTEXT (other_context), FALSE);
1020
1021   /* check if the contexts are descendants or the root nodes are the same */
1022   return context->priv->sharegroup != NULL
1023       && context->priv->sharegroup == other_context->priv->sharegroup;
1024 }
1025
1026 /**
1027  * gst_gl_context_create:
1028  * @context: a #GstGLContext:
1029  * @other_context: (allow-none): a #GstGLContext to share OpenGL objects with
1030  * @error: (allow-none): a #GError
1031  *
1032  * Creates an OpenGL context with the specified @other_context as a context
1033  * to share shareable OpenGL objects with.  See the OpenGL specification for
1034  * what is shared between OpenGL contexts.
1035  *
1036  * Since 1.20, the configuration can be overriden with the environment variable
1037  * `GST_GL_CONFIG` which is a stringified #GstStructure as would be returned
1038  * from gst_gl_context_get_config().  If `GST_GL_CONFIG` is not set, then the
1039  * config will be chosen from @other_context by calling
1040  * gst_gl_context_get_config() on @other_context.  Otherwise, a default
1041  * configuration is used.
1042  *
1043  * Calling gst_gl_context_request_config()) before calling
1044  * gst_gl_context_create() will override the config from @other_context but
1045  * will not override the `GST_GL_CONFIG` environment variable.
1046  *
1047  * If an error occurs, and @error is not %NULL, then @error will contain
1048  * details of the error and %FALSE will be returned.
1049  *
1050  * Should only be called once.
1051  *
1052  * Returns: whether the context could successfully be created
1053  *
1054  * Since: 1.4
1055  */
1056 gboolean
1057 gst_gl_context_create (GstGLContext * context,
1058     GstGLContext * other_context, GError ** error)
1059 {
1060   gboolean alive = FALSE;
1061
1062   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1063   g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
1064
1065   GST_DEBUG_OBJECT (context, " other_context:%" GST_PTR_FORMAT, other_context);
1066
1067   _ensure_window (context);
1068
1069   g_mutex_lock (&context->priv->render_lock);
1070
1071   if (!context->priv->created) {
1072     g_weak_ref_set (&context->priv->other_context_ref, other_context);
1073     context->priv->error = error;
1074     if (other_context == NULL)
1075       context->priv->sharegroup = _context_share_group_new ();
1076     else
1077       context->priv->sharegroup =
1078           _context_share_group_ref (other_context->priv->sharegroup);
1079
1080     context->priv->gl_thread = g_thread_new ("gstglcontext",
1081         (GThreadFunc) gst_gl_context_create_thread, context);
1082
1083     while (!context->priv->created)
1084       g_cond_wait (&context->priv->create_cond, &context->priv->render_lock);
1085
1086     GST_INFO_OBJECT (context, "gl thread created");
1087   }
1088
1089   alive = context->priv->alive;
1090
1091   g_mutex_unlock (&context->priv->render_lock);
1092
1093   return alive;
1094 }
1095
1096 static gboolean
1097 _create_context_info (GstGLContext * context, GstGLAPI gl_api, gint * gl_major,
1098     gint * gl_minor, GError ** error)
1099 {
1100   const GstGLFuncs *gl;
1101   guint maj = 0, min = 0;
1102   GLenum gl_err = GL_NO_ERROR;
1103   const gchar *opengl_version = NULL;
1104
1105   gl = context->gl_vtable;
1106
1107   if (!gl->GetString || !gl->GetString (GL_VERSION)) {
1108     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1109         "glGetString not defined or returned invalid value");
1110     return FALSE;
1111   }
1112
1113   if (!gl->GetString (GL_SHADING_LANGUAGE_VERSION)) {
1114     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1115         "No GL shader support available");
1116     return FALSE;
1117   }
1118
1119   GST_INFO_OBJECT (context, "GL_VERSION: %s",
1120       GST_STR_NULL ((const gchar *) gl->GetString (GL_VERSION)));
1121   GST_INFO_OBJECT (context, "GL_SHADING_LANGUAGE_VERSION: %s",
1122       GST_STR_NULL ((const gchar *)
1123           gl->GetString (GL_SHADING_LANGUAGE_VERSION)));
1124   GST_INFO_OBJECT (context, "GL_VENDOR: %s",
1125       GST_STR_NULL ((const gchar *) gl->GetString (GL_VENDOR)));
1126   GST_INFO_OBJECT (context, "GL_RENDERER: %s",
1127       GST_STR_NULL ((const gchar *) gl->GetString (GL_RENDERER)));
1128
1129   gl_err = gl->GetError ();
1130   if (gl_err != GL_NO_ERROR) {
1131     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1132         "glGetString error: 0x%x", gl_err);
1133     return FALSE;
1134   }
1135
1136   opengl_version = (const gchar *) gl->GetString (GL_VERSION);
1137   if (opengl_version && g_str_has_prefix (opengl_version, "OpenGL ES "))
1138     opengl_version = &opengl_version[10];
1139
1140   if (opengl_version)
1141     sscanf (opengl_version, "%d.%d", &maj, &min);
1142
1143   /* OpenGL > 1.2.0 */
1144   if (gl_api & GST_GL_API_OPENGL || gl_api & GST_GL_API_OPENGL3) {
1145     if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
1146       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS,
1147           "OpenGL >= 1.2.0 required, found %u.%u", maj, min);
1148       return FALSE;
1149     }
1150   }
1151
1152   if (gl_major)
1153     *gl_major = maj;
1154   if (gl_minor)
1155     *gl_minor = min;
1156
1157   return TRUE;
1158 }
1159
1160 static GstGLAPI
1161 _compiled_api (void)
1162 {
1163   GstGLAPI ret = GST_GL_API_NONE;
1164
1165 #if GST_GL_HAVE_OPENGL
1166   ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
1167 #endif
1168 #if GST_GL_HAVE_GLES2
1169   ret |= GST_GL_API_GLES2;
1170 #endif
1171
1172   return ret;
1173 }
1174
1175 static void
1176 _unlock_create_thread (GstGLContext * context)
1177 {
1178   context->priv->created = TRUE;
1179   GST_INFO_OBJECT (context, "gl thread running");
1180   g_cond_signal (&context->priv->create_cond);
1181   g_mutex_unlock (&context->priv->render_lock);
1182 }
1183
1184 static GString *
1185 _build_extension_string (GstGLContext * context)
1186 {
1187   const GstGLFuncs *gl = context->gl_vtable;
1188   GString *ext_g_str = g_string_sized_new (1024);
1189   const gchar *ext_const_c_str = NULL;
1190   GLint i = 0;
1191   GLint n = 0;
1192
1193   gl->GetIntegerv (GL_NUM_EXTENSIONS, &n);
1194
1195   for (i = 0; i < n; i++) {
1196     ext_const_c_str = (const gchar *) gl->GetStringi (GL_EXTENSIONS, i);
1197     if (ext_const_c_str)
1198       g_string_append_printf (ext_g_str, "%s ", ext_const_c_str);
1199   }
1200
1201   return ext_g_str;
1202 }
1203
1204 //gboolean
1205 //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error)
1206 static gpointer
1207 gst_gl_context_create_thread (GstGLContext * context)
1208 {
1209   GstGLContextClass *context_class;
1210   GstGLWindowClass *window_class;
1211   GstGLAPI compiled_api, user_api, gl_api, display_api;
1212   gchar *api_string;
1213   gchar *compiled_api_s;
1214   gchar *user_api_s;
1215   gchar *display_api_s;
1216   const gchar *user_choice;
1217   GError **error;
1218   GstGLContext *other_context;
1219   GstStructure *config;
1220
1221   g_mutex_lock (&context->priv->render_lock);
1222
1223   GST_DEBUG_OBJECT (context, "Creating thread");
1224
1225   error = context->priv->error;
1226   other_context = g_weak_ref_get (&context->priv->other_context_ref);
1227
1228   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1229   window_class = GST_GL_WINDOW_GET_CLASS (context->window);
1230
1231   display_api = gst_gl_display_get_gl_api_unlocked (context->display);
1232   if (display_api == GST_GL_API_NONE) {
1233     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1234         "Cannot create context with satisfying requested apis "
1235         "(display has no GL api!)");
1236     goto failure;
1237   }
1238
1239   if (window_class->open) {
1240     if (!window_class->open (context->window, error)) {
1241       GST_WARNING_OBJECT (context, "Failed to open window");
1242       g_assert (error == NULL || *error != NULL);
1243       goto failure;
1244     }
1245   }
1246
1247   compiled_api = _compiled_api ();
1248   compiled_api_s = gst_gl_api_to_string (compiled_api);
1249
1250   user_choice = g_getenv ("GST_GL_API");
1251   user_api = gst_gl_api_from_string (user_choice);
1252   user_api_s = gst_gl_api_to_string (user_api);
1253
1254   display_api_s = gst_gl_api_to_string (display_api);
1255
1256   if ((user_api & compiled_api & display_api) == GST_GL_API_NONE) {
1257     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1258         "Cannot create context with the user requested api (%s).  "
1259         "We have support for (%s), display api (%s)", user_api_s,
1260         compiled_api_s, display_api_s);
1261     g_free (user_api_s);
1262     g_free (compiled_api_s);
1263     g_free (display_api_s);
1264     goto failure;
1265   }
1266
1267   {
1268     const gchar *config_str = g_getenv ("GST_GL_CONFIG");
1269     if (config_str) {
1270       GstStructure *config = gst_structure_from_string (config_str, NULL);
1271       if (!config) {
1272         g_set_error (error, GST_GL_CONTEXT_ERROR,
1273             GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1274             "could not construct OpenGL config from the \'GST_GL_CONFIG\' "
1275             "environment variable");
1276         g_free (compiled_api_s);
1277         g_free (user_api_s);
1278         g_free (display_api_s);
1279         goto failure;
1280       }
1281       if (!gst_gl_context_request_config (context, gst_structure_copy (config))) {
1282         GST_WARNING_OBJECT (context,
1283             "failed to request config %" GST_PTR_FORMAT, config);
1284       } else {
1285         GST_INFO_OBJECT (context, "requesting config from environment %"
1286             GST_PTR_FORMAT, config);
1287       }
1288       gst_structure_free (config);
1289     } else if (other_context && !context->priv->requested_config) {
1290       GstStructure *config = gst_gl_context_get_config (other_context);
1291       if (config) {
1292         if (!gst_gl_context_request_config (context,
1293                 gst_structure_copy (config))) {
1294           GST_WARNING_OBJECT (context,
1295               "failed to request config %" GST_PTR_FORMAT, config);
1296         } else {
1297           GST_INFO_OBJECT (context, "requesting config from other context %"
1298               GST_PTR_FORMAT " %" GST_PTR_FORMAT, other_context, config);
1299         }
1300         gst_structure_free (config);
1301       }
1302     }
1303   }
1304
1305   if (context_class->choose_format &&
1306       !context_class->choose_format (context, error)) {
1307     GST_WARNING_OBJECT (context, "Failed to choose format");
1308     g_assert (error == NULL || *error != NULL);
1309     g_free (compiled_api_s);
1310     g_free (user_api_s);
1311     g_free (display_api_s);
1312     goto failure;
1313   }
1314
1315   GST_INFO_OBJECT (context,
1316       "Attempting to create opengl context. user chosen api(s) (%s), "
1317       "compiled api support (%s) display api (%s)", user_api_s, compiled_api_s,
1318       display_api_s);
1319
1320   if (!context_class->create_context (context,
1321           compiled_api & user_api & display_api, other_context, error)) {
1322     GST_WARNING_OBJECT (context, "Failed to create context");
1323     g_assert (error == NULL || *error != NULL);
1324     g_free (compiled_api_s);
1325     g_free (user_api_s);
1326     g_free (display_api_s);
1327     goto failure;
1328   }
1329   GST_INFO_OBJECT (context, "created context");
1330
1331   if (!gst_gl_context_activate (context, TRUE)) {
1332     g_set_error (error, GST_GL_CONTEXT_ERROR,
1333         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
1334         "Failed to activate the GL Context");
1335     g_free (compiled_api_s);
1336     g_free (user_api_s);
1337     g_free (display_api_s);
1338     goto failure;
1339   }
1340
1341   gl_api = gst_gl_context_get_gl_api (context);
1342   g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY);
1343
1344   api_string = gst_gl_api_to_string (gl_api);
1345   GST_INFO_OBJECT (context, "available GL APIs: %s", api_string);
1346
1347   if ((config = gst_gl_context_get_config (context))) {
1348     GST_DEBUG_OBJECT (context, "Chosen config %" GST_PTR_FORMAT, config);
1349     gst_structure_free (config);
1350   }
1351
1352   if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) {
1353     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1354         "failed to create context, context "
1355         "could not provide correct api. user (%s), compiled (%s), context (%s)",
1356         user_api_s, compiled_api_s, api_string);
1357     g_free (api_string);
1358     g_free (compiled_api_s);
1359     g_free (user_api_s);
1360     g_free (display_api_s);
1361     goto failure;
1362   }
1363
1364   g_free (api_string);
1365   g_free (compiled_api_s);
1366   g_free (user_api_s);
1367   g_free (display_api_s);
1368
1369   GST_DEBUG_OBJECT (context, "Filling info");
1370   if (!gst_gl_context_fill_info (context, error)) {
1371     g_assert (error == NULL || *error != NULL);
1372     goto failure;
1373   }
1374
1375   context->priv->alive = TRUE;
1376
1377 #if !defined(GST_DISABLE_GST_DEBUG)
1378   _gst_gl_debug_enable (context);
1379 #endif
1380
1381   if (other_context) {
1382     GST_DEBUG_OBJECT (context, "Unreffing other_context %" GST_PTR_FORMAT,
1383         other_context);
1384     gst_object_unref (other_context);
1385   }
1386
1387   /* unlocking of the render_lock happens when the
1388    * context's loop is running from inside that loop */
1389   gst_gl_window_send_message_async (context->window,
1390       (GstGLWindowCB) _unlock_create_thread, context, NULL);
1391
1392   gst_gl_window_run (context->window);
1393
1394   GST_INFO_OBJECT (context, "loop exited");
1395
1396   g_mutex_lock (&context->priv->render_lock);
1397   context->priv->alive = FALSE;
1398
1399   gst_gl_context_activate (context, FALSE);
1400
1401   context_class->destroy_context (context);
1402
1403   /* User supplied callback */
1404   if (context->window->close)
1405     context->window->close (context->window->close_data);
1406
1407   /* window specific shutdown */
1408   if (window_class->close) {
1409     window_class->close (context->window);
1410   }
1411
1412   context->priv->created = FALSE;
1413   g_cond_signal (&context->priv->destroy_cond);
1414   g_mutex_unlock (&context->priv->render_lock);
1415
1416   return NULL;
1417
1418 failure:
1419   {
1420     if (other_context)
1421       gst_object_unref (other_context);
1422
1423     /* A context that fails to be created is considered created but not alive
1424      * and will never be able to be alive as creation can't happen */
1425     context->priv->created = TRUE;
1426     g_cond_signal (&context->priv->create_cond);
1427     g_mutex_unlock (&context->priv->render_lock);
1428     return NULL;
1429   }
1430 }
1431
1432 /**
1433  * gst_gl_context_destroy:
1434  * @context: a #GstGLContext:
1435  *
1436  * Destroys an OpenGL context.
1437  *
1438  * Should only be called after gst_gl_context_create() has been successfully
1439  * called for this context.
1440  *
1441  * Since: 1.6
1442  */
1443 void
1444 gst_gl_context_destroy (GstGLContext * context)
1445 {
1446   GstGLContextClass *context_class;
1447
1448   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1449   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1450   g_return_if_fail (context_class->destroy_context != NULL);
1451
1452   context_class->destroy_context (context);
1453 }
1454
1455 /**
1456  * gst_gl_context_fill_info:
1457  * @context: a #GstGLContext:
1458  * @error: (allow-none): a #GError to fill on failure
1459  *
1460  * Fills @context's info (version, extensions, vtable, etc) from the GL
1461  * context in the current thread.  Typically used with wrapped contexts to
1462  * allow wrapped contexts to be used as regular #GstGLContext's.
1463  *
1464  * Since: 1.6
1465  */
1466 gboolean
1467 gst_gl_context_fill_info (GstGLContext * context, GError ** error)
1468 {
1469   GstGLFuncs *gl;
1470   GString *ext_g_str = NULL;
1471   const gchar *ext_const_c_str = NULL;
1472   GstGLAPI gl_api;
1473   gboolean ret;
1474
1475   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1476   g_return_val_if_fail (context->priv->active_thread == g_thread_self (),
1477       FALSE);
1478
1479   gl = context->gl_vtable;
1480   gl_api = gst_gl_context_get_gl_api (context);
1481
1482   gl->GetError = gst_gl_context_get_proc_address (context, "glGetError");
1483   gl->GetString = gst_gl_context_get_proc_address (context, "glGetString");
1484   gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi");
1485   gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv");
1486
1487   if (!gl->GetError || !gl->GetString) {
1488     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1489         "could not GetProcAddress core opengl functions");
1490     goto failure;
1491   }
1492
1493   /* gl api specific code */
1494   ret = _create_context_info (context, gl_api, &context->priv->gl_major,
1495       &context->priv->gl_minor, error);
1496
1497   if (!ret) {
1498     g_assert (error == NULL || *error != NULL);
1499     goto failure;
1500   }
1501
1502   /* GL core contexts and GLES3 */
1503   if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3)
1504     ext_g_str = _build_extension_string (context);
1505
1506   if (ext_g_str && ext_g_str->len) {
1507     GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str);
1508     _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1509         context->priv->gl_minor, ext_g_str->str);
1510
1511     context->priv->gl_exts = g_string_free (ext_g_str, FALSE);
1512   } else {
1513     ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS);
1514     if (!ext_const_c_str)
1515       ext_const_c_str = "";
1516
1517     GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str);
1518     _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1519         context->priv->gl_minor, ext_const_c_str);
1520
1521     context->priv->gl_exts = g_strdup (ext_const_c_str);
1522   }
1523
1524   if (gl_api & GST_GL_API_OPENGL3
1525       && !gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 4, 1)
1526       && !gst_gl_check_extension ("GL_ARB_ES2_compatibility",
1527           context->priv->gl_exts)) {
1528     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1529         "An opengl3 context created but the required ES2 compatibility was not found");
1530     goto failure;
1531   }
1532
1533   gst_gl_context_apply_quirks (context);
1534
1535   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
1536     /* XXX: vfunc? */
1537 #if GST_GL_HAVE_PLATFORM_GLX
1538     if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_GLX
1539         && !gst_gl_context_glx_fill_info (context, error))
1540       goto failure;
1541 #endif
1542 #if GST_GL_HAVE_PLATFORM_EGL
1543     if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_EGL
1544         && !gst_gl_context_egl_fill_info (context, error))
1545       goto failure;
1546 #endif
1547   }
1548
1549   return TRUE;
1550
1551 failure:
1552   return FALSE;
1553 }
1554
1555 /**
1556  * gst_gl_context_get_gl_context:
1557  * @context: a #GstGLContext:
1558  *
1559  * Gets the backing OpenGL context used by @context.
1560  *
1561  * Returns: The platform specific backing OpenGL context
1562  *
1563  * Since: 1.4
1564  */
1565 guintptr
1566 gst_gl_context_get_gl_context (GstGLContext * context)
1567 {
1568   GstGLContextClass *context_class;
1569   guintptr result;
1570
1571   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1572   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1573   g_return_val_if_fail (context_class->get_gl_context != NULL, 0);
1574
1575   result = context_class->get_gl_context (context);
1576
1577   return result;
1578 }
1579
1580 /**
1581  * gst_gl_context_get_gl_platform:
1582  * @context: a #GstGLContext:
1583  *
1584  * Gets the OpenGL platform that used by @context.
1585  *
1586  * Returns: The platform specific backing OpenGL context
1587  *
1588  * Since: 1.4
1589  */
1590 GstGLPlatform
1591 gst_gl_context_get_gl_platform (GstGLContext * context)
1592 {
1593   GstGLContextClass *context_class;
1594
1595   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1596   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1597   g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
1598
1599   return context_class->get_gl_platform (context);
1600 }
1601
1602 /**
1603  * gst_gl_context_get_display:
1604  * @context: a #GstGLContext:
1605  *
1606  * Returns: (transfer full): the #GstGLDisplay associated with this @context
1607  *
1608  * Since: 1.4
1609  */
1610 GstGLDisplay *
1611 gst_gl_context_get_display (GstGLContext * context)
1612 {
1613   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1614
1615   return gst_object_ref (context->display);
1616 }
1617
1618 typedef struct
1619 {
1620   GstGLContext *context;
1621   GstGLContextThreadFunc func;
1622   gpointer data;
1623 } RunGenericData;
1624
1625 static void
1626 _gst_gl_context_thread_run_generic (RunGenericData * data)
1627 {
1628   GST_TRACE_OBJECT (data->context, "running function:%p data:%p", data->func,
1629       data->data);
1630
1631   data->func (data->context, data->data);
1632 }
1633
1634 /**
1635  * gst_gl_context_thread_add:
1636  * @context: a #GstGLContext
1637  * @func: (scope call): a #GstGLContextThreadFunc
1638  * @data: (closure): user data to call @func with
1639  *
1640  * Execute @func in the OpenGL thread of @context with @data
1641  *
1642  * MT-safe
1643  *
1644  * Since: 1.4
1645  */
1646 void
1647 gst_gl_context_thread_add (GstGLContext * context,
1648     GstGLContextThreadFunc func, gpointer data)
1649 {
1650   GstGLWindow *window;
1651   RunGenericData rdata;
1652
1653   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1654   g_return_if_fail (func != NULL);
1655
1656   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1657     g_return_if_fail (context->priv->active_thread == g_thread_self ());
1658
1659   if (context->priv->active_thread == g_thread_self ()) {
1660     func (context, data);
1661     return;
1662   }
1663
1664   rdata.context = context;
1665   rdata.data = data;
1666   rdata.func = func;
1667
1668   window = gst_gl_context_get_window (context);
1669
1670   gst_gl_window_send_message (window,
1671       GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata);
1672
1673   gst_object_unref (window);
1674 }
1675
1676 /**
1677  * gst_gl_context_get_gl_version:
1678  * @context: a #GstGLContext
1679  * @maj: (out): resulting major version
1680  * @min: (out): resulting minor version
1681  *
1682  * Returns the OpenGL version implemented by @context.  See
1683  * gst_gl_context_get_gl_api() for retrieving the OpenGL api implemented by
1684  * @context.
1685  *
1686  * Since: 1.4
1687  */
1688 void
1689 gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min)
1690 {
1691   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1692   g_return_if_fail (!(maj == NULL && min == NULL));
1693
1694   if (maj)
1695     *maj = context->priv->gl_major;
1696
1697   if (min)
1698     *min = context->priv->gl_minor;
1699 }
1700
1701 /**
1702  * gst_gl_context_check_gl_version:
1703  * @context: a #GstGLContext
1704  * @api: api type required
1705  * @maj: major version required
1706  * @min: minor version required
1707  *
1708  * Returns: whether OpenGL context implements the required api and specified
1709  * version.
1710  *
1711  * Since: 1.4
1712  */
1713 gboolean
1714 gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api,
1715     gint maj, gint min)
1716 {
1717   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1718
1719   if (maj > context->priv->gl_major)
1720     return FALSE;
1721
1722   if ((gst_gl_context_get_gl_api (context) & api) == GST_GL_API_NONE)
1723     return FALSE;
1724
1725   if (maj < context->priv->gl_major)
1726     return TRUE;
1727
1728   if (min > context->priv->gl_minor)
1729     return FALSE;
1730
1731   return TRUE;
1732 }
1733
1734 /**
1735  * gst_gl_context_check_feature:
1736  * @context: a #GstGLContext
1737  * @feature: a platform specific feature
1738  *
1739  * Check for an OpenGL @feature being supported.
1740  *
1741  * Note: Most features require that the context be created before it is
1742  * possible to determine their existence and so will fail if that is not the
1743  * case.
1744  *
1745  * Returns: Whether @feature is supported by @context
1746  *
1747  * Since: 1.4
1748  */
1749 gboolean
1750 gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
1751 {
1752   GstGLContextClass *context_class;
1753
1754   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1755   g_return_val_if_fail (feature != NULL, FALSE);
1756
1757   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1758
1759   if (g_strstr_len (feature, 3, "GL_"))
1760     return gst_gl_check_extension (feature, context->priv->gl_exts);
1761
1762   if (!context_class->check_feature)
1763     return FALSE;
1764
1765   return context_class->check_feature (context, feature);
1766 }
1767
1768 /**
1769  * gst_gl_context_get_current:
1770  *
1771  * See also gst_gl_context_activate().
1772  *
1773  * Returns: (transfer none) (nullable): the #GstGLContext active in the current thread or %NULL
1774  *
1775  * Since: 1.6
1776  */
1777 GstGLContext *
1778 gst_gl_context_get_current (void)
1779 {
1780   return g_private_get (&current_context_key);
1781 }
1782
1783 /**
1784  * gst_gl_context_is_shared:
1785  * @context: a #GstGLContext
1786  *
1787  * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
1788  *
1789  * Since: 1.8
1790  */
1791 gboolean
1792 gst_gl_context_is_shared (GstGLContext * context)
1793 {
1794   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1795
1796   if (!context->priv->sharegroup)
1797     return FALSE;
1798
1799   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1800     g_return_val_if_fail (context->priv->active_thread, FALSE);
1801   else
1802     g_return_val_if_fail (context->priv->alive, FALSE);
1803
1804   return _context_share_group_is_shared (context->priv->sharegroup);
1805 }
1806
1807 /**
1808  * gst_gl_context_set_shared_with:
1809  * @context: a wrapped #GstGLContext
1810  * @share: another #GstGLContext
1811  *
1812  * Will internally set @context as shared with @share
1813  *
1814  * Since: 1.8
1815  */
1816 void
1817 gst_gl_context_set_shared_with (GstGLContext * context, GstGLContext * share)
1818 {
1819   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1820   g_return_if_fail (GST_IS_GL_CONTEXT (share));
1821   g_return_if_fail (!gst_gl_context_is_shared (context));
1822   /* XXX: may be a little too strict */
1823   g_return_if_fail (GST_IS_GL_WRAPPED_CONTEXT (context));
1824
1825   if (context->priv->sharegroup)
1826     _context_share_group_unref (context->priv->sharegroup);
1827   context->priv->sharegroup =
1828       _context_share_group_ref (share->priv->sharegroup);
1829 }
1830
1831 static void
1832 gst_gl_context_default_get_gl_platform_version (GstGLContext * context,
1833     gint * major, gint * minor)
1834 {
1835   if (major)
1836     *major = 0;
1837   if (minor)
1838     *minor = 0;
1839 }
1840
1841 /**
1842  * gst_gl_context_get_gl_platform_version:
1843  * @context: a #GstGLContext
1844  * @major: (out): return for the major version
1845  * @minor: (out): return for the minor version
1846  *
1847  * Get the version of the OpenGL platform (GLX, EGL, etc) used.  Only valid
1848  * after a call to gst_gl_context_create().
1849  */
1850 void
1851 gst_gl_context_get_gl_platform_version (GstGLContext * context, gint * major,
1852     gint * minor)
1853 {
1854   GstGLContextClass *context_class;
1855
1856   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1857   g_return_if_fail (major != NULL);
1858   g_return_if_fail (minor != NULL);
1859   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1860   g_return_if_fail (context_class->get_gl_platform_version != NULL);
1861
1862   context_class->get_gl_platform_version (context, major, minor);
1863 }
1864
1865 /**
1866  * gst_gl_context_swap_buffers:
1867  * @context: a #GstGLContext
1868  *
1869  * Swap the front and back buffers on the window attached to @context.
1870  * This will display the frame on the next refresh cycle.
1871  */
1872 void
1873 gst_gl_context_swap_buffers (GstGLContext * context)
1874 {
1875   GstGLContextClass *context_class;
1876
1877   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1878   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1879   g_return_if_fail (context_class->swap_buffers != NULL);
1880
1881   context_class->swap_buffers (context);
1882 }
1883
1884 /**
1885  * gst_gl_context_get_config:
1886  * @context: the #GstGLContext
1887  *
1888  * Retrieve the OpenGL configuration for this context.  The context must
1889  * have been successfully created for this function to return a valid value.
1890  *
1891  * Not all implementations currently support retrieving the config and will
1892  * return %NULL when not supported.
1893  *
1894  * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context.
1895  *
1896  * Since: 1.20
1897  */
1898 GstStructure *
1899 gst_gl_context_get_config (GstGLContext * context)
1900 {
1901   GstGLContextClass *context_class;
1902
1903   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1904   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1905   if (!context_class->get_config) {
1906     GST_FIXME_OBJECT (context, "does not support retrieving a config");
1907     return NULL;
1908   }
1909
1910   return context_class->get_config (context);
1911 }
1912
1913 /**
1914  * gst_gl_context_request_config:
1915  * @context: the #GstGLContext
1916  * @gl_config: (nullable) (transfer full): a configuration structure for
1917  *             configuring the OpenGL context
1918  *
1919  * Set the OpenGL configuration for this context.  The context must not
1920  * have been created for this function to succeed.  Setting a %NULL
1921  * @config has the affect of removing any specific configuration request.
1922  *
1923  * Not all implementations currently support retrieving the config and this
1924  * function will return FALSE when not supported.
1925  *
1926  * Note that calling this function may cause a subsequent
1927  * gst_gl_context_create() to fail if @config could not be matched with
1928  * the platform-specific configuration.
1929  *
1930  * Note that the actual config used may be differ from the requested values.
1931  *
1932  * Returns: whether @gl_config could be successfully set on @context
1933  *
1934  * Since: 1.20
1935  */
1936 gboolean
1937 gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config)
1938 {
1939   GstGLContextClass *context_class;
1940   gboolean ret;
1941
1942   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1943   g_return_val_if_fail (context->priv->created == FALSE, FALSE);
1944   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1945   if (!context_class->request_config) {
1946     gst_structure_free (gl_config);
1947     GST_FIXME_OBJECT (context, "does not support requesting a config");
1948     return FALSE;
1949   }
1950
1951   ret = context_class->request_config (context, gst_structure_copy (gl_config));
1952   if (ret) {
1953     if (context->priv->requested_config)
1954       gst_structure_free (context->priv->requested_config);
1955     context->priv->requested_config = gl_config;
1956   } else {
1957     gst_structure_free (gl_config);
1958   }
1959
1960   return ret;
1961 }
1962
1963 static GstGLAPI
1964 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
1965 {
1966   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1967
1968   return context_wrap->available_apis;
1969 }
1970
1971 static guintptr
1972 gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
1973 {
1974   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1975
1976   return context_wrap->handle;
1977 }
1978
1979 static GstGLPlatform
1980 gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
1981 {
1982   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1983
1984   return context_wrap->platform;
1985 }
1986
1987 static gboolean
1988 gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
1989 {
1990   if (activate) {
1991     GThread *old_thread = context->priv->gl_thread;
1992     context->priv->gl_thread = g_thread_ref (g_thread_self ());
1993     if (old_thread) {
1994       g_thread_unref (old_thread);
1995     }
1996   } else {
1997     if (context->priv->gl_thread) {
1998       g_thread_unref (context->priv->gl_thread);
1999       context->priv->gl_thread = NULL;
2000     }
2001   }
2002
2003   return TRUE;
2004 }
2005
2006 static gpointer
2007 _structure_copy_if_set (gpointer data, gpointer user_data)
2008 {
2009   GstStructure *ret = NULL;
2010
2011   if (data)
2012     ret = gst_structure_copy (data);
2013   return ret;
2014 }
2015
2016 static GstStructure *
2017 gst_gl_wrapped_context_get_config (GstGLContext * context)
2018 {
2019   GstStructure *ret;
2020
2021   ret = g_object_dup_data (G_OBJECT (context),
2022       GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME,
2023       (GDuplicateFunc) _structure_copy_if_set, NULL);
2024   if (ret) {
2025     GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT,
2026         ret);
2027     return ret;
2028   } else {
2029     GST_FIXME_OBJECT (context, "wrapped context could not retrieve config. "
2030         "The application may be missing a call to gst_gl_context_fill_info() "
2031         "or the specific platform implemention is not implemented for "
2032         "retrieving the config from a wrapped OpenGL context.");
2033     return NULL;
2034   }
2035 }
2036
2037 static void
2038 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
2039 {
2040   GstGLContextClass *context_class = (GstGLContextClass *) klass;
2041
2042   context_class->get_gl_context =
2043       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
2044   context_class->get_gl_api =
2045       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
2046   context_class->get_gl_platform =
2047       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
2048   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
2049   context_class->get_config =
2050       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_config);
2051 }
2052
2053 static void
2054 gst_gl_wrapped_context_init (GstGLWrappedContext * context)
2055 {
2056 }
2057
2058 G_GNUC_INTERNAL gboolean
2059 _gst_gl_context_debug_is_enabled (GstGLContext * context)
2060 {
2061 #if !defined(GST_DISABLE_GST_DEBUG)
2062   GstDebugLevel level;
2063
2064   level = gst_debug_category_get_threshold (gst_gl_debug);
2065
2066   if (level < GST_LEVEL_WARNING) {
2067     GST_CAT_INFO_OBJECT (gst_gl_context_debug, context, "Disabling GL context "
2068         "debugging (gldebug category debug level < warning)");
2069     return FALSE;
2070   }
2071   return TRUE;
2072 #else
2073   return FALSE;
2074 #endif
2075 }