• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
load_opengl_module(gpointer user_data)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
load_gles2_module(gpointer user_data)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
load_self_module(gpointer user_data)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 *
_context_share_group_new(void)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 *
_context_share_group_ref(struct ContextShareGroup * share)185 _context_share_group_ref (struct ContextShareGroup *share)
186 {
187   g_atomic_int_inc (&share->refcount);
188   return share;
189 }
190 
191 static void
_context_share_group_unref(struct ContextShareGroup * share)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
_context_share_group_is_shared(struct ContextShareGroup * share)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
gst_gl_context_error_quark(void)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
_ensure_window(GstGLContext * context)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
gst_gl_context_init(GstGLContext * context)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
gst_gl_context_class_init(GstGLContextClass * klass)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
_init_debug(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 *
gst_gl_context_new(GstGLDisplay * display)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 *
gst_gl_context_new_wrapped(GstGLDisplay * display,guintptr handle,GstGLPlatform context_type,GstGLAPI available_apis)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: The OpenGL context handle current in the calling thread or %NULL
498  *
499  * Since: 1.6
500  */
501 guintptr
gst_gl_context_get_current_gl_context(GstGLPlatform context_type)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: a function pointer for @name, or %NULL
547  *
548  * Since: 1.6
549  */
550 gpointer
gst_gl_context_get_proc_address_with_platform(GstGLPlatform context_type,GstGLAPI gl_api,const gchar * name)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
gst_gl_context_get_current_gl_api(GstGLPlatform platform,guint * major,guint * minor)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
gst_gl_context_finalize(GObject * object)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
gst_gl_context_activate(GstGLContext * context,gboolean activate)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): The #GThread, @context is current in or NULL
811  *
812  * Since: 1.6
813  */
814 GThread *
gst_gl_context_get_thread(GstGLContext * context)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
gst_gl_context_get_gl_api(GstGLContext * context)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: a function pointer or %NULL
881  *
882  * Since: 1.4
883  */
884 gpointer
gst_gl_context_get_proc_address(GstGLContext * context,const gchar * name)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: an address pointing to @name or %NULL
912  *
913  * Since: 1.4
914  */
915 gpointer
gst_gl_context_default_get_proc_address(GstGLAPI gl_api,const gchar * name)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
gst_gl_context_set_window(GstGLContext * context,GstGLWindow * window)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 *
gst_gl_context_get_window(GstGLContext * context)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
gst_gl_context_can_share(GstGLContext * context,GstGLContext * other_context)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
gst_gl_context_create(GstGLContext * context,GstGLContext * other_context,GError ** error)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
_create_context_info(GstGLContext * context,GstGLAPI gl_api,gint * gl_major,gint * gl_minor,GError ** error)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
_compiled_api(void)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
_unlock_create_thread(GstGLContext * context)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 *
_build_extension_string(GstGLContext * context)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
gst_gl_context_create_thread(GstGLContext * context)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
gst_gl_context_destroy(GstGLContext * context)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
gst_gl_context_fill_info(GstGLContext * context,GError ** error)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   /* Does not implement OES_vertex_array_object properly, see
1534    * https://bugzilla.gnome.org/show_bug.cgi?id=750185 */
1535   if (g_strcmp0 ((const gchar *) gl->GetString (GL_VENDOR),
1536           "Imagination Technologies") == 0
1537       && g_strcmp0 ((const gchar *) gl->GetString (GL_RENDERER),
1538           "PowerVR SGX 544MP") == 0) {
1539     gl->GenVertexArrays = NULL;
1540     gl->DeleteVertexArrays = NULL;
1541     gl->BindVertexArray = NULL;
1542     gl->IsVertexArray = NULL;
1543   }
1544 
1545   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
1546     /* XXX: vfunc? */
1547 #if GST_GL_HAVE_PLATFORM_GLX
1548     if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_GLX
1549         && !gst_gl_context_glx_fill_info (context, error))
1550       goto failure;
1551 #endif
1552 #if GST_GL_HAVE_PLATFORM_EGL
1553     if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_EGL
1554         && !gst_gl_context_egl_fill_info (context, error))
1555       goto failure;
1556 #endif
1557   }
1558 
1559   return TRUE;
1560 
1561 failure:
1562   return FALSE;
1563 }
1564 
1565 /**
1566  * gst_gl_context_get_gl_context:
1567  * @context: a #GstGLContext:
1568  *
1569  * Gets the backing OpenGL context used by @context.
1570  *
1571  * Returns: The platform specific backing OpenGL context
1572  *
1573  * Since: 1.4
1574  */
1575 guintptr
gst_gl_context_get_gl_context(GstGLContext * context)1576 gst_gl_context_get_gl_context (GstGLContext * context)
1577 {
1578   GstGLContextClass *context_class;
1579   guintptr result;
1580 
1581   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1582   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1583   g_return_val_if_fail (context_class->get_gl_context != NULL, 0);
1584 
1585   result = context_class->get_gl_context (context);
1586 
1587   return result;
1588 }
1589 
1590 /**
1591  * gst_gl_context_get_gl_platform:
1592  * @context: a #GstGLContext:
1593  *
1594  * Gets the OpenGL platform that used by @context.
1595  *
1596  * Returns: The platform specific backing OpenGL context
1597  *
1598  * Since: 1.4
1599  */
1600 GstGLPlatform
gst_gl_context_get_gl_platform(GstGLContext * context)1601 gst_gl_context_get_gl_platform (GstGLContext * context)
1602 {
1603   GstGLContextClass *context_class;
1604 
1605   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1606   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1607   g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
1608 
1609   return context_class->get_gl_platform (context);
1610 }
1611 
1612 /**
1613  * gst_gl_context_get_display:
1614  * @context: a #GstGLContext:
1615  *
1616  * Returns: (transfer full): the #GstGLDisplay associated with this @context
1617  *
1618  * Since: 1.4
1619  */
1620 GstGLDisplay *
gst_gl_context_get_display(GstGLContext * context)1621 gst_gl_context_get_display (GstGLContext * context)
1622 {
1623   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1624 
1625   return gst_object_ref (context->display);
1626 }
1627 
1628 typedef struct
1629 {
1630   GstGLContext *context;
1631   GstGLContextThreadFunc func;
1632   gpointer data;
1633 } RunGenericData;
1634 
1635 static void
_gst_gl_context_thread_run_generic(RunGenericData * data)1636 _gst_gl_context_thread_run_generic (RunGenericData * data)
1637 {
1638   GST_TRACE_OBJECT (data->context, "running function:%p data:%p", data->func,
1639       data->data);
1640 
1641   data->func (data->context, data->data);
1642 }
1643 
1644 /**
1645  * gst_gl_context_thread_add:
1646  * @context: a #GstGLContext
1647  * @func: (scope call): a #GstGLContextThreadFunc
1648  * @data: (closure): user data to call @func with
1649  *
1650  * Execute @func in the OpenGL thread of @context with @data
1651  *
1652  * MT-safe
1653  *
1654  * Since: 1.4
1655  */
1656 void
gst_gl_context_thread_add(GstGLContext * context,GstGLContextThreadFunc func,gpointer data)1657 gst_gl_context_thread_add (GstGLContext * context,
1658     GstGLContextThreadFunc func, gpointer data)
1659 {
1660   GstGLWindow *window;
1661   RunGenericData rdata;
1662 
1663   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1664   g_return_if_fail (func != NULL);
1665 
1666   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1667     g_return_if_fail (context->priv->active_thread == g_thread_self ());
1668 
1669   if (context->priv->active_thread == g_thread_self ()) {
1670     func (context, data);
1671     return;
1672   }
1673 
1674   rdata.context = context;
1675   rdata.data = data;
1676   rdata.func = func;
1677 
1678   window = gst_gl_context_get_window (context);
1679 
1680   gst_gl_window_send_message (window,
1681       GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata);
1682 
1683   gst_object_unref (window);
1684 }
1685 
1686 /**
1687  * gst_gl_context_get_gl_version:
1688  * @context: a #GstGLContext
1689  * @maj: (out): resulting major version
1690  * @min: (out): resulting minor version
1691  *
1692  * Returns the OpenGL version implemented by @context.  See
1693  * gst_gl_context_get_gl_api() for retrieving the OpenGL api implemented by
1694  * @context.
1695  *
1696  * Since: 1.4
1697  */
1698 void
gst_gl_context_get_gl_version(GstGLContext * context,gint * maj,gint * min)1699 gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min)
1700 {
1701   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1702   g_return_if_fail (!(maj == NULL && min == NULL));
1703 
1704   if (maj)
1705     *maj = context->priv->gl_major;
1706 
1707   if (min)
1708     *min = context->priv->gl_minor;
1709 }
1710 
1711 /**
1712  * gst_gl_context_check_gl_version:
1713  * @context: a #GstGLContext
1714  * @api: api type required
1715  * @maj: major version required
1716  * @min: minor version required
1717  *
1718  * Returns: whether OpenGL context implements the required api and specified
1719  * version.
1720  *
1721  * Since: 1.4
1722  */
1723 gboolean
gst_gl_context_check_gl_version(GstGLContext * context,GstGLAPI api,gint maj,gint min)1724 gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api,
1725     gint maj, gint min)
1726 {
1727   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1728 
1729   if (maj > context->priv->gl_major)
1730     return FALSE;
1731 
1732   if ((gst_gl_context_get_gl_api (context) & api) == GST_GL_API_NONE)
1733     return FALSE;
1734 
1735   if (maj < context->priv->gl_major)
1736     return TRUE;
1737 
1738   if (min > context->priv->gl_minor)
1739     return FALSE;
1740 
1741   return TRUE;
1742 }
1743 
1744 /**
1745  * gst_gl_context_check_feature:
1746  * @context: a #GstGLContext
1747  * @feature: a platform specific feature
1748  *
1749  * Check for an OpenGL @feature being supported.
1750  *
1751  * Note: Most features require that the context be created before it is
1752  * possible to determine their existence and so will fail if that is not the
1753  * case.
1754  *
1755  * Returns: Whether @feature is supported by @context
1756  *
1757  * Since: 1.4
1758  */
1759 gboolean
gst_gl_context_check_feature(GstGLContext * context,const gchar * feature)1760 gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
1761 {
1762   GstGLContextClass *context_class;
1763 
1764   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1765   g_return_val_if_fail (feature != NULL, FALSE);
1766 
1767   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1768 
1769   if (g_strstr_len (feature, 3, "GL_"))
1770     return gst_gl_check_extension (feature, context->priv->gl_exts);
1771 
1772   if (!context_class->check_feature)
1773     return FALSE;
1774 
1775   return context_class->check_feature (context, feature);
1776 }
1777 
1778 /**
1779  * gst_gl_context_get_current:
1780  *
1781  * See also gst_gl_context_activate().
1782  *
1783  * Returns: (transfer none): the #GstGLContext active in the current thread or %NULL
1784  *
1785  * Since: 1.6
1786  */
1787 GstGLContext *
gst_gl_context_get_current(void)1788 gst_gl_context_get_current (void)
1789 {
1790   return g_private_get (&current_context_key);
1791 }
1792 
1793 /**
1794  * gst_gl_context_is_shared:
1795  * @context: a #GstGLContext
1796  *
1797  * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
1798  *
1799  * Since: 1.8
1800  */
1801 gboolean
gst_gl_context_is_shared(GstGLContext * context)1802 gst_gl_context_is_shared (GstGLContext * context)
1803 {
1804   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1805 
1806   if (!context->priv->sharegroup)
1807     return FALSE;
1808 
1809   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1810     g_return_val_if_fail (context->priv->active_thread, FALSE);
1811   else
1812     g_return_val_if_fail (context->priv->alive, FALSE);
1813 
1814   return _context_share_group_is_shared (context->priv->sharegroup);
1815 }
1816 
1817 /**
1818  * gst_gl_context_set_shared_with:
1819  * @context: a wrapped #GstGLContext
1820  * @share: another #GstGLContext
1821  *
1822  * Will internally set @context as shared with @share
1823  *
1824  * Since: 1.8
1825  */
1826 void
gst_gl_context_set_shared_with(GstGLContext * context,GstGLContext * share)1827 gst_gl_context_set_shared_with (GstGLContext * context, GstGLContext * share)
1828 {
1829   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1830   g_return_if_fail (GST_IS_GL_CONTEXT (share));
1831   g_return_if_fail (!gst_gl_context_is_shared (context));
1832   /* XXX: may be a little too strict */
1833   g_return_if_fail (GST_IS_GL_WRAPPED_CONTEXT (context));
1834 
1835   if (context->priv->sharegroup)
1836     _context_share_group_unref (context->priv->sharegroup);
1837   context->priv->sharegroup =
1838       _context_share_group_ref (share->priv->sharegroup);
1839 }
1840 
1841 static void
gst_gl_context_default_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)1842 gst_gl_context_default_get_gl_platform_version (GstGLContext * context,
1843     gint * major, gint * minor)
1844 {
1845   if (major)
1846     *major = 0;
1847   if (minor)
1848     *minor = 0;
1849 }
1850 
1851 /**
1852  * gst_gl_context_get_gl_platform_version:
1853  * @context: a #GstGLContext
1854  * @major: (out): return for the major version
1855  * @minor: (out): return for the minor version
1856  *
1857  * Get the version of the OpenGL platform (GLX, EGL, etc) used.  Only valid
1858  * after a call to gst_gl_context_create().
1859  */
1860 void
gst_gl_context_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)1861 gst_gl_context_get_gl_platform_version (GstGLContext * context, gint * major,
1862     gint * minor)
1863 {
1864   GstGLContextClass *context_class;
1865 
1866   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1867   g_return_if_fail (major != NULL);
1868   g_return_if_fail (minor != NULL);
1869   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1870   g_return_if_fail (context_class->get_gl_platform_version != NULL);
1871 
1872   context_class->get_gl_platform_version (context, major, minor);
1873 }
1874 
1875 /**
1876  * gst_gl_context_swap_buffers:
1877  * @context: a #GstGLContext
1878  *
1879  * Swap the front and back buffers on the window attached to @context.
1880  * This will display the frame on the next refresh cycle.
1881  */
1882 void
gst_gl_context_swap_buffers(GstGLContext * context)1883 gst_gl_context_swap_buffers (GstGLContext * context)
1884 {
1885   GstGLContextClass *context_class;
1886 
1887   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1888   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1889   g_return_if_fail (context_class->swap_buffers != NULL);
1890 
1891   context_class->swap_buffers (context);
1892 }
1893 
1894 /**
1895  * gst_gl_context_get_config:
1896  * @context: the #GstGLContext
1897  *
1898  * Retrieve the OpenGL configuration for this context.  The context must
1899  * have been successfully created for this function to return a valid value.
1900  *
1901  * Not all implementations currently support retrieving the config and will
1902  * return %NULL when not supported.
1903  *
1904  * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context.
1905  *
1906  * Since: 1.20
1907  */
1908 GstStructure *
gst_gl_context_get_config(GstGLContext * context)1909 gst_gl_context_get_config (GstGLContext * context)
1910 {
1911   GstGLContextClass *context_class;
1912 
1913   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1914   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1915   if (!context_class->get_config) {
1916     GST_FIXME_OBJECT (context, "does not support retrieving a config");
1917     return NULL;
1918   }
1919 
1920   return context_class->get_config (context);
1921 }
1922 
1923 /**
1924  * gst_gl_context_request_config:
1925  * @context: the #GstGLContext
1926  * @gl_config: (nullable) (transfer full): a configuration structure for
1927  *             configuring the OpenGL context
1928  *
1929  * Set the OpenGL configuration for this context.  The context must not
1930  * have been created for this function to succeed.  Setting a %NULL
1931  * @config has the affect of removing any specific configuration request.
1932  *
1933  * Not all implementations currently support retrieving the config and this
1934  * function will return FALSE when not supported.
1935  *
1936  * Note that calling this function may cause a subsequent
1937  * gst_gl_context_create() to fail if @config could not be matched with
1938  * the platform-specific configuration.
1939  *
1940  * Note that the actual config used may be differ from the requested values.
1941  *
1942  * Returns: whether @gl_config could be successfully set on @context
1943  *
1944  * Since: 1.20
1945  */
1946 gboolean
gst_gl_context_request_config(GstGLContext * context,GstStructure * gl_config)1947 gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config)
1948 {
1949   GstGLContextClass *context_class;
1950   gboolean ret;
1951 
1952   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1953   g_return_val_if_fail (context->priv->created == FALSE, FALSE);
1954   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1955   if (!context_class->request_config) {
1956     gst_structure_free (gl_config);
1957     GST_FIXME_OBJECT (context, "does not support requesting a config");
1958     return FALSE;
1959   }
1960 
1961   ret = context_class->request_config (context, gst_structure_copy (gl_config));
1962   if (ret) {
1963     if (context->priv->requested_config)
1964       gst_structure_free (context->priv->requested_config);
1965     context->priv->requested_config = gl_config;
1966   } else {
1967     gst_structure_free (gl_config);
1968   }
1969 
1970   return ret;
1971 }
1972 
1973 static GstGLAPI
gst_gl_wrapped_context_get_gl_api(GstGLContext * context)1974 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
1975 {
1976   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1977 
1978   return context_wrap->available_apis;
1979 }
1980 
1981 static guintptr
gst_gl_wrapped_context_get_gl_context(GstGLContext * context)1982 gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
1983 {
1984   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1985 
1986   return context_wrap->handle;
1987 }
1988 
1989 static GstGLPlatform
gst_gl_wrapped_context_get_gl_platform(GstGLContext * context)1990 gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
1991 {
1992   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1993 
1994   return context_wrap->platform;
1995 }
1996 
1997 static gboolean
gst_gl_wrapped_context_activate(GstGLContext * context,gboolean activate)1998 gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
1999 {
2000   if (activate) {
2001     GThread *old_thread = context->priv->gl_thread;
2002     context->priv->gl_thread = g_thread_ref (g_thread_self ());
2003     if (old_thread) {
2004       g_thread_unref (old_thread);
2005     }
2006   } else {
2007     if (context->priv->gl_thread) {
2008       g_thread_unref (context->priv->gl_thread);
2009       context->priv->gl_thread = NULL;
2010     }
2011   }
2012 
2013   return TRUE;
2014 }
2015 
2016 static gpointer
_structure_copy_if_set(gpointer data,gpointer user_data)2017 _structure_copy_if_set (gpointer data, gpointer user_data)
2018 {
2019   GstStructure *ret = NULL;
2020 
2021   if (data)
2022     ret = gst_structure_copy (data);
2023   return ret;
2024 }
2025 
2026 static GstStructure *
gst_gl_wrapped_context_get_config(GstGLContext * context)2027 gst_gl_wrapped_context_get_config (GstGLContext * context)
2028 {
2029   GstStructure *ret;
2030 
2031   ret = g_object_dup_data (G_OBJECT (context),
2032       GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME,
2033       (GDuplicateFunc) _structure_copy_if_set, NULL);
2034   if (ret) {
2035     GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT,
2036         ret);
2037     return ret;
2038   } else {
2039     GST_FIXME_OBJECT (context, "wrapped context could not retrieve config. "
2040         "The application may be missing a call to gst_gl_context_fill_info() "
2041         "or the specific platform implemention is not implemented for "
2042         "retrieving the config from a wrapped OpenGL context.");
2043     return NULL;
2044   }
2045 }
2046 
2047 static void
gst_gl_wrapped_context_class_init(GstGLWrappedContextClass * klass)2048 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
2049 {
2050   GstGLContextClass *context_class = (GstGLContextClass *) klass;
2051 
2052   context_class->get_gl_context =
2053       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
2054   context_class->get_gl_api =
2055       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
2056   context_class->get_gl_platform =
2057       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
2058   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
2059   context_class->get_config =
2060       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_config);
2061 }
2062 
2063 static void
gst_gl_wrapped_context_init(GstGLWrappedContext * context)2064 gst_gl_wrapped_context_init (GstGLWrappedContext * context)
2065 {
2066 }
2067 
2068 G_GNUC_INTERNAL gboolean
_gst_gl_context_debug_is_enabled(GstGLContext * context)2069 _gst_gl_context_debug_is_enabled (GstGLContext * context)
2070 {
2071 #if !defined(GST_DISABLE_GST_DEBUG)
2072   GstDebugLevel level;
2073 
2074   level = gst_debug_category_get_threshold (gst_gl_debug);
2075 
2076   if (level < GST_LEVEL_WARNING) {
2077     GST_CAT_INFO_OBJECT (gst_gl_context_debug, context, "Disabling GL context "
2078         "debugging (gldebug category debug level < warning)");
2079     return FALSE;
2080   }
2081   return TRUE;
2082 #else
2083   return FALSE;
2084 #endif
2085 }
2086