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 
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35 
36 #if defined(ANDROID) || defined(__ANDROID__)
37 /* Avoid a linker error with _isoc99_sscanf() when building a shared library
38  * for android
39  */
40 #define _GNU_SOURCE
41 #endif
42 
43 #include "gstglcontext.h"
44 #include <gst/gl/gl.h>
45 
46 #include <gmodule.h>
47 #include <string.h>
48 #include <stdio.h>
49 
50 #include "gstglcontext_private.h"
51 #include "gstglfeature.h"
52 #include "gstglfeature_private.h"
53 #include "gstglfuncs.h"
54 
55 #ifndef GL_NUM_EXTENSIONS
56 #define GL_NUM_EXTENSIONS 0x0000821d
57 #endif
58 
59 #if GST_GL_HAVE_PLATFORM_GLX
60 #include "x11/gstglcontext_glx.h"
61 #endif
62 #if GST_GL_HAVE_PLATFORM_EGL
63 #include "egl/gstglcontext_egl.h"
64 #endif
65 #if GST_GL_HAVE_PLATFORM_CGL
66 #include "cocoa/gstglcontext_cocoa.h"
67 #endif
68 #if GST_GL_HAVE_PLATFORM_WGL
69 #include "win32/gstglcontext_wgl.h"
70 #endif
71 #if GST_GL_HAVE_PLATFORM_EAGL
72 #include "eagl/gstglcontext_eagl.h"
73 #endif
74 
75 extern void _gst_gl_debug_enable (GstGLContext * context);
76 
77 static GPrivate current_context_key;
78 
79 static GModule *module_self;
80 static GOnce module_self_gonce = G_ONCE_INIT;
81 
82 #if GST_GL_HAVE_OPENGL
83 static GOnce module_opengl_gonce = G_ONCE_INIT;
84 static GModule *module_opengl;
85 
86 static gpointer
load_opengl_module(gpointer user_data)87 load_opengl_module (gpointer user_data)
88 {
89 #ifdef GST_GL_LIBGL_MODULE_NAME
90   module_opengl = g_module_open (GST_GL_LIBGL_MODULE_NAME, G_MODULE_BIND_LAZY);
91 #else
92   /* On Linux the .so is only in -dev packages, try with a real soname
93    * Proper compilers will optimize away the strcmp */
94   if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
95     module_opengl = g_module_open ("libGL.so.1", G_MODULE_BIND_LAZY);
96 
97   /* This automatically handles the suffix and even .la files */
98   if (!module_opengl)
99     module_opengl = g_module_open ("libGL", G_MODULE_BIND_LAZY);
100 #endif
101 
102   return NULL;
103 }
104 #endif
105 
106 #if GST_GL_HAVE_GLES2
107 static GOnce module_gles2_gonce = G_ONCE_INIT;
108 static GModule *module_gles2;
109 
110 static gpointer
load_gles2_module(gpointer user_data)111 load_gles2_module (gpointer user_data)
112 {
113 #ifdef GST_GL_LIBGLESV2_MODULE_NAME
114   module_gles2 =
115       g_module_open (GST_GL_LIBGLESV2_MODULE_NAME, G_MODULE_BIND_LAZY);
116 #else
117   /* On Linux the .so is only in -dev packages, try with a real soname
118    * Proper compilers will optimize away the strcmp */
119   if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
120     module_gles2 = g_module_open ("libGLESv2.so.2", G_MODULE_BIND_LAZY);
121 
122   /* This automatically handles the suffix and even .la files */
123   if (!module_gles2)
124     module_gles2 = g_module_open ("libGLESv2", G_MODULE_BIND_LAZY);
125 
126 #endif
127 
128   return NULL;
129 }
130 #endif
131 
132 static gpointer
load_self_module(gpointer user_data)133 load_self_module (gpointer user_data)
134 {
135   module_self = g_module_open (NULL, G_MODULE_BIND_LAZY);
136 
137   return NULL;
138 }
139 
140 /* Context sharedness is tracked by a refcounted pointer stored in each context
141  * object to track complex creation/deletion scenarios.  As a result,
142  * sharedness can only be successfully validated between two GstGLContext's
143  * where one is not a wrapped context.
144  *
145  * As there is no API at the winsys level to tell whether two OpenGL contexts
146  * can share GL resources, this is the next best thing.
147  *
148  * XXX: we may need a way to associate two wrapped GstGLContext's as being
149  * shared however I have not come across a use case that requries this yet.
150  */
151 struct ContextShareGroup
152 {
153   volatile int refcount;
154 };
155 
156 static struct ContextShareGroup *
_context_share_group_new(void)157 _context_share_group_new (void)
158 {
159   struct ContextShareGroup *ret = g_new0 (struct ContextShareGroup, 1);
160 
161   ret->refcount = 1;
162 
163   return ret;
164 }
165 
166 static struct ContextShareGroup *
_context_share_group_ref(struct ContextShareGroup * share)167 _context_share_group_ref (struct ContextShareGroup *share)
168 {
169   g_atomic_int_inc (&share->refcount);
170   return share;
171 }
172 
173 static void
_context_share_group_unref(struct ContextShareGroup * share)174 _context_share_group_unref (struct ContextShareGroup *share)
175 {
176   if (g_atomic_int_dec_and_test (&share->refcount))
177     g_free (share);
178 }
179 
180 static gboolean
_context_share_group_is_shared(struct ContextShareGroup * share)181 _context_share_group_is_shared (struct ContextShareGroup *share)
182 {
183   return g_atomic_int_get (&share->refcount) > 1;
184 }
185 
186 #define GST_CAT_DEFAULT gst_gl_context_debug
187 GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
188 GST_DEBUG_CATEGORY_STATIC (gst_gl_debug);
189 
190 static void _init_debug (void);
191 
192 static gpointer gst_gl_context_create_thread (GstGLContext * context);
193 static void gst_gl_context_finalize (GObject * object);
194 static void gst_gl_context_default_get_gl_platform_version (GstGLContext *
195     context, gint * major, gint * minor);
196 
197 struct _GstGLContextPrivate
198 {
199   GThread *gl_thread;
200   GThread *active_thread;
201 
202   /* conditions */
203   GMutex render_lock;
204   GCond create_cond;
205   GCond destroy_cond;
206 
207   gboolean created;
208   gboolean alive;
209 
210   GWeakRef other_context_ref;
211   struct ContextShareGroup *sharegroup;
212   GError **error;
213 
214   gint gl_major;
215   gint gl_minor;
216 
217   gchar *gl_exts;
218 };
219 
220 typedef struct
221 {
222   GstGLContext parent;
223 
224   guintptr handle;
225   GstGLPlatform platform;
226   GstGLAPI available_apis;
227 } GstGLWrappedContext;
228 
229 typedef struct
230 {
231   GstGLContextClass parent;
232 } GstGLWrappedContextClass;
233 
234 #define gst_gl_context_parent_class parent_class
235 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLContext, gst_gl_context,
236     GST_TYPE_OBJECT);
237 
238 #define GST_TYPE_GL_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type())
239 static GType gst_gl_wrapped_context_get_type (void);
240 G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
241     GST_TYPE_GL_CONTEXT);
242 
243 #define GST_GL_WRAPPED_CONTEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContext))
244 #define GST_GL_WRAPPED_CONTEXT_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_CONTEXT, GstGLContextClass))
245 #define GST_IS_GL_WRAPPED_CONTEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WRAPPED_CONTEXT))
246 #define GST_IS_GL_WRAPPED_CONTEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WRAPPED_CONTEXT))
247 #define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContextClass))
248 
249 GQuark
gst_gl_context_error_quark(void)250 gst_gl_context_error_quark (void)
251 {
252   return g_quark_from_static_string ("gst-gl-context-error-quark");
253 }
254 
255 static void
_ensure_window(GstGLContext * context)256 _ensure_window (GstGLContext * context)
257 {
258   GstGLWindow *window;
259 
260   if (context->window)
261     return;
262 
263   window = gst_gl_display_create_window (context->display);
264 
265   gst_gl_context_set_window (context, window);
266 
267   gst_object_unref (window);
268 }
269 
270 static void
gst_gl_context_init(GstGLContext * context)271 gst_gl_context_init (GstGLContext * context)
272 {
273   context->priv = gst_gl_context_get_instance_private (context);
274 
275   context->window = NULL;
276   context->gl_vtable = g_slice_alloc0 (sizeof (GstGLFuncs));
277 
278   g_mutex_init (&context->priv->render_lock);
279 
280   g_cond_init (&context->priv->create_cond);
281   g_cond_init (&context->priv->destroy_cond);
282   context->priv->created = FALSE;
283 
284   g_weak_ref_init (&context->priv->other_context_ref, NULL);
285 }
286 
287 static void
gst_gl_context_class_init(GstGLContextClass * klass)288 gst_gl_context_class_init (GstGLContextClass * klass)
289 {
290   klass->get_proc_address =
291       GST_DEBUG_FUNCPTR (gst_gl_context_default_get_proc_address);
292   klass->get_gl_platform_version =
293       GST_DEBUG_FUNCPTR (gst_gl_context_default_get_gl_platform_version);
294 
295   G_OBJECT_CLASS (klass)->finalize = gst_gl_context_finalize;
296 
297   _init_debug ();
298 }
299 
300 static void
_init_debug(void)301 _init_debug (void)
302 {
303   static volatile gsize _init = 0;
304 
305   if (g_once_init_enter (&_init)) {
306     GST_DEBUG_CATEGORY_INIT (gst_gl_context_debug, "glcontext", 0,
307         "glcontext element");
308     GST_DEBUG_CATEGORY_INIT (gst_gl_debug, "gldebug", 0, "OpenGL Debugging");
309     g_once_init_leave (&_init, 1);
310   }
311 }
312 
313 /**
314  * gst_gl_context_new:
315  * @display: a #GstGLDisplay
316  *
317  * Create a new #GstGLContext with the specified @display
318  *
319  * Returns: a new #GstGLContext
320  *
321  * Since: 1.4
322  */
323 GstGLContext *
gst_gl_context_new(GstGLDisplay * display)324 gst_gl_context_new (GstGLDisplay * display)
325 {
326   GstGLContext *context = NULL;
327   const gchar *user_choice;
328 
329   _init_debug ();
330 
331   user_choice = g_getenv ("GST_GL_PLATFORM");
332   GST_INFO ("creating a context for display %" GST_PTR_FORMAT
333       ", user choice:%s", display, user_choice);
334 #if GST_GL_HAVE_PLATFORM_CGL
335   if (!context && (!user_choice || g_strstr_len (user_choice, 3, "cgl")))
336     context = GST_GL_CONTEXT (gst_gl_context_cocoa_new (display));
337 #endif
338 #if GST_GL_HAVE_PLATFORM_GLX
339   if (!context && (!user_choice || g_strstr_len (user_choice, 3, "glx")))
340     context = GST_GL_CONTEXT (gst_gl_context_glx_new (display));
341 #endif
342 #if GST_GL_HAVE_PLATFORM_EGL
343   if (!context && (!user_choice || g_strstr_len (user_choice, 3, "egl")))
344     context = GST_GL_CONTEXT (gst_gl_context_egl_new (display));
345 #endif
346 #if GST_GL_HAVE_PLATFORM_WGL
347   if (!context && (!user_choice || g_strstr_len (user_choice, 3, "wgl")))
348     context = GST_GL_CONTEXT (gst_gl_context_wgl_new (display));
349 #endif
350 #if GST_GL_HAVE_PLATFORM_EAGL
351   if (!context && (!user_choice || g_strstr_len (user_choice, 4, "eagl")))
352     context = GST_GL_CONTEXT (gst_gl_context_eagl_new (display));
353 #endif
354 
355   if (!context) {
356     /* subclass returned a NULL context */
357     GST_WARNING ("Could not create context. user specified %s",
358         user_choice ? user_choice : "(null)");
359 
360     return NULL;
361   }
362 
363   context->display = gst_object_ref (display);
364 
365   GST_DEBUG_OBJECT (context,
366       "Done creating context for display %" GST_PTR_FORMAT " (user_choice:%s)",
367       display, user_choice);
368 
369   return context;
370 }
371 
372 /**
373  * gst_gl_context_new_wrapped:
374  * @display: a #GstGLDisplay
375  * @handle: the OpenGL context to wrap
376  * @context_type: a #GstGLPlatform specifying the type of context in @handle
377  * @available_apis: a #GstGLAPI containing the available OpenGL apis in @handle
378  *
379  * Wraps an existing OpenGL context into a #GstGLContext.
380  *
381  * Note: The caller is responsible for ensuring that the OpenGL context
382  * represented by @handle stays alive while the returned #GstGLContext is
383  * active.
384  *
385  * Returns: (transfer full): a #GstGLContext wrapping @handle
386  *
387  * Since: 1.4
388  */
389 GstGLContext *
gst_gl_context_new_wrapped(GstGLDisplay * display,guintptr handle,GstGLPlatform context_type,GstGLAPI available_apis)390 gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
391     GstGLPlatform context_type, GstGLAPI available_apis)
392 {
393   GstGLContext *context;
394   GstGLWrappedContext *context_wrap = NULL;
395   GstGLContextClass *context_class;
396   GstGLAPI display_api;
397 
398   _init_debug ();
399 
400   display_api = gst_gl_display_get_gl_api (display);
401   g_return_val_if_fail ((display_api & available_apis) != GST_GL_API_NONE,
402       NULL);
403 
404   context_wrap = g_object_new (GST_TYPE_GL_WRAPPED_CONTEXT, NULL);
405   gst_object_ref_sink (context_wrap);
406 
407   if (!context_wrap) {
408     /* subclass returned a NULL context */
409     GST_ERROR ("Could not wrap existing context");
410 
411     return NULL;
412   }
413 
414   context = (GstGLContext *) context_wrap;
415 
416   context->display = gst_object_ref (display);
417   context->priv->sharegroup = _context_share_group_new ();
418   context_wrap->handle = handle;
419   context_wrap->platform = context_type;
420   context_wrap->available_apis = available_apis;
421 
422   context_class = GST_GL_CONTEXT_GET_CLASS (context);
423 
424 #if GST_GL_HAVE_PLATFORM_GLX
425   if (context_type == GST_GL_PLATFORM_GLX) {
426     context_class->get_current_context = gst_gl_context_glx_get_current_context;
427     context_class->get_proc_address = gst_gl_context_glx_get_proc_address;
428   }
429 #endif
430 #if GST_GL_HAVE_PLATFORM_EGL
431   if (context_type == GST_GL_PLATFORM_EGL) {
432     context_class->get_current_context = gst_gl_context_egl_get_current_context;
433     context_class->get_proc_address = gst_gl_context_egl_get_proc_address;
434   }
435 #endif
436 #if GST_GL_HAVE_PLATFORM_CGL
437   if (context_type == GST_GL_PLATFORM_CGL) {
438     context_class->get_current_context =
439         gst_gl_context_cocoa_get_current_context;
440     context_class->get_proc_address = gst_gl_context_default_get_proc_address;
441   }
442 #endif
443 #if GST_GL_HAVE_PLATFORM_WGL
444   if (context_type == GST_GL_PLATFORM_WGL) {
445     context_class->get_current_context = gst_gl_context_wgl_get_current_context;
446     context_class->get_proc_address = gst_gl_context_wgl_get_proc_address;
447   }
448 #endif
449 #if GST_GL_HAVE_PLATFORM_EAGL
450   if (context_type == GST_GL_PLATFORM_EAGL) {
451     context_class->get_current_context =
452         gst_gl_context_eagl_get_current_context;
453     context_class->get_proc_address = gst_gl_context_default_get_proc_address;
454   }
455 #endif
456 
457   if (!context_class->get_current_context) {
458     /* we don't have API support */
459     gst_object_unref (context);
460     return NULL;
461   }
462 
463   return context;
464 }
465 
466 /**
467  * gst_gl_context_get_current_gl_context:
468  * @context_type: a #GstGLPlatform specifying the type of context to retrieve
469  *
470  * Returns: The OpenGL context handle current in the calling thread or %NULL
471  *
472  * Since: 1.6
473  */
474 guintptr
gst_gl_context_get_current_gl_context(GstGLPlatform context_type)475 gst_gl_context_get_current_gl_context (GstGLPlatform context_type)
476 {
477   guintptr handle = 0;
478 
479   _init_debug ();
480 
481 #if GST_GL_HAVE_PLATFORM_GLX
482   if (!handle && (context_type & GST_GL_PLATFORM_GLX) != 0)
483     handle = gst_gl_context_glx_get_current_context ();
484 #endif
485 #if GST_GL_HAVE_PLATFORM_EGL
486   if (!handle && (context_type & GST_GL_PLATFORM_EGL) != 0)
487     handle = gst_gl_context_egl_get_current_context ();
488 #endif
489 #if GST_GL_HAVE_PLATFORM_CGL
490   if (!handle && (context_type & GST_GL_PLATFORM_CGL) != 0)
491     handle = gst_gl_context_cocoa_get_current_context ();
492 #endif
493 #if GST_GL_HAVE_PLATFORM_WGL
494   if (!handle && (context_type & GST_GL_PLATFORM_WGL) != 0)
495     handle = gst_gl_context_wgl_get_current_context ();
496 #endif
497 #if GST_GL_HAVE_PLATFORM_EAGL
498   if (!handle && (context_type & GST_GL_PLATFORM_EAGL) != 0)
499     handle = gst_gl_context_eagl_get_current_context ();
500 #endif
501 
502   if (!handle)
503     GST_WARNING ("Could not retrieve current context");
504 
505   return handle;
506 }
507 
508 /**
509  * gst_gl_context_get_proc_address_with_platform:
510  * @context_type: a #GstGLPlatform
511  * @gl_api: a #GstGLAPI
512  * @name: the name of the function to retrieve
513  *
514  * Attempts to use the @context_type specific GetProcAddress implementations
515  * to retreive @name.
516  *
517  * See also gst_gl_context_get_proc_address().
518  *
519  * Returns: a function pointer for @name, or %NULL
520  *
521  * Since: 1.6
522  */
523 gpointer
gst_gl_context_get_proc_address_with_platform(GstGLPlatform context_type,GstGLAPI gl_api,const gchar * name)524 gst_gl_context_get_proc_address_with_platform (GstGLPlatform context_type,
525     GstGLAPI gl_api, const gchar * name)
526 {
527   gpointer ret = NULL;
528 
529 #if GST_GL_HAVE_PLATFORM_GLX
530   if (!ret && (context_type & GST_GL_PLATFORM_GLX) != 0)
531     ret = gst_gl_context_glx_get_proc_address (gl_api, name);
532 #endif
533 #if GST_GL_HAVE_PLATFORM_EGL
534   if (!ret && (context_type & GST_GL_PLATFORM_EGL) != 0)
535     ret = gst_gl_context_egl_get_proc_address (gl_api, name);
536 #endif
537 #if GST_GL_HAVE_PLATFORM_WGL
538   if (!ret && (context_type & GST_GL_PLATFORM_WGL) != 0)
539     ret = gst_gl_context_wgl_get_proc_address (gl_api, name);
540 #endif
541   /* CGL and EAGL rely on the default impl */
542 
543   if (!ret)
544     ret = gst_gl_context_default_get_proc_address (gl_api, name);
545 
546   return ret;
547 }
548 
549 /**
550  * gst_gl_context_get_current_gl_api:
551  * @platform: the #GstGLPlatform to retrieve the API for
552  * @major: (out) (allow-none): the major version
553  * @minor: (out) (allow-none): the minor version
554  *
555  * If an error occurs, @major and @minor are not modified and %GST_GL_API_NONE is
556  * returned.
557  *
558  * Returns: The version supported by the OpenGL context current in the calling
559  *          thread or %GST_GL_API_NONE
560  *
561  * Since: 1.6
562  */
563 GstGLAPI
gst_gl_context_get_current_gl_api(GstGLPlatform platform,guint * major,guint * minor)564 gst_gl_context_get_current_gl_api (GstGLPlatform platform, guint * major,
565     guint * minor)
566 {
567   const GLubyte *(GSTGLAPI * GetString) (GLenum name);
568 #if GST_GL_HAVE_OPENGL
569   void (GSTGLAPI * GetIntegerv) (GLenum name, GLuint * n);
570 #endif
571   const gchar *version;
572   gint maj, min, n;
573   GstGLAPI ret = (1U << 31);
574 
575   _init_debug ();
576 
577   while (ret != GST_GL_API_NONE) {
578     /* FIXME: attempt to delve into the platform specific GetProcAddress */
579     GetString =
580         gst_gl_context_get_proc_address_with_platform (platform, ret,
581         "glGetString");
582 #if GST_GL_HAVE_OPENGL
583     GetIntegerv =
584         gst_gl_context_get_proc_address_with_platform (platform, ret,
585         "glGetIntegerv");
586 #endif
587     if (!GetString) {
588       goto next;
589     }
590 
591     version = (const gchar *) GetString (GL_VERSION);
592     if (!version)
593       goto next;
594 
595     /* strlen (x.x) == 3 */
596     n = strlen (version);
597     if (n < 3)
598       goto next;
599 
600     if (g_strstr_len (version, 9, "OpenGL ES")) {
601       /* strlen (OpenGL ES x.x) == 13 */
602       if (n < 13)
603         goto next;
604 
605       sscanf (&version[10], "%d.%d", &maj, &min);
606 
607       if (maj <= 0 || min < 0)
608         goto next;
609 
610       if (maj == 1) {
611         ret = GST_GL_API_GLES1;
612         break;
613       } else if (maj == 2 || maj == 3) {
614         ret = GST_GL_API_GLES2;
615         break;
616       }
617 
618       goto next;
619     } else {
620       sscanf (version, "%d.%d", &maj, &min);
621 
622       if (maj <= 0 || min < 0)
623         goto next;
624 
625 #if GST_GL_HAVE_OPENGL
626       if (GetIntegerv && (maj > 3 || (maj == 3 && min > 1))) {
627         GLuint context_flags = 0;
628 
629         ret = GST_GL_API_NONE;
630         GetIntegerv (GL_CONTEXT_PROFILE_MASK, &context_flags);
631         if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT)
632           ret |= GST_GL_API_OPENGL3;
633         if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
634           ret |= GST_GL_API_OPENGL;
635         break;
636       }
637 #endif
638       ret = GST_GL_API_OPENGL;
639       break;
640     }
641 
642   next:
643     /* iterate through the apis */
644     ret >>= 1;
645   }
646 
647   if (ret == GST_GL_API_NONE)
648     return GST_GL_API_NONE;
649 
650   if (major)
651     *major = maj;
652   if (minor)
653     *minor = min;
654 
655   return ret;
656 }
657 
658 static void
gst_gl_context_finalize(GObject * object)659 gst_gl_context_finalize (GObject * object)
660 {
661   GstGLContext *context = GST_GL_CONTEXT (object);
662 
663   if (context->window) {
664     gst_gl_window_set_resize_callback (context->window, NULL, NULL, NULL);
665     gst_gl_window_set_draw_callback (context->window, NULL, NULL, NULL);
666 
667     g_mutex_lock (&context->priv->render_lock);
668     if (context->priv->alive) {
669       GST_INFO_OBJECT (context, "send quit gl window loop");
670       gst_gl_window_quit (context->window);
671 
672       GST_INFO_OBJECT (context, "joining gl thread");
673       while (context->priv->alive)
674         g_cond_wait (&context->priv->destroy_cond, &context->priv->render_lock);
675       GST_INFO_OBJECT (context, "gl thread joined");
676 
677       if (context->priv->gl_thread) {
678         g_thread_unref (context->priv->gl_thread);
679         context->priv->gl_thread = NULL;
680       }
681     }
682     g_mutex_unlock (&context->priv->render_lock);
683 
684     gst_gl_window_set_close_callback (context->window, NULL, NULL, NULL);
685     gst_object_unref (context->window);
686     context->window = NULL;
687   }
688 
689   if (context->priv->active_thread) {
690     g_thread_unref (context->priv->active_thread);
691     context->priv->active_thread = NULL;
692   }
693 
694   if (context->priv->gl_thread) {
695     g_thread_unref (context->priv->gl_thread);
696     context->priv->gl_thread = NULL;
697   }
698 
699   if (context->priv->sharegroup) {
700     _context_share_group_unref (context->priv->sharegroup);
701     context->priv->sharegroup = NULL;
702   }
703 
704   if (context->display) {
705     gst_object_unref (context->display);
706     context->display = NULL;
707   }
708 
709   if (context->gl_vtable) {
710     g_slice_free (GstGLFuncs, context->gl_vtable);
711     context->gl_vtable = NULL;
712   }
713 
714   g_mutex_clear (&context->priv->render_lock);
715 
716   g_cond_clear (&context->priv->create_cond);
717   g_cond_clear (&context->priv->destroy_cond);
718 
719   g_free (context->priv->gl_exts);
720   g_weak_ref_clear (&context->priv->other_context_ref);
721 
722   GST_DEBUG_OBJECT (context, "End of finalize");
723   G_OBJECT_CLASS (gst_gl_context_parent_class)->finalize (object);
724 }
725 
726 /**
727  * gst_gl_context_activate:
728  * @context: a #GstGLContext
729  * @activate: %TRUE to activate, %FALSE to deactivate
730  *
731  * (De)activate the OpenGL context represented by this @context.
732  *
733  * In OpenGL terms, calls eglMakeCurrent or similar with this context and the
734  * currently set window.  See gst_gl_context_set_window() for details.
735  *
736  * Returns: Whether the activation succeeded
737  *
738  * Since: 1.4
739  */
740 gboolean
gst_gl_context_activate(GstGLContext * context,gboolean activate)741 gst_gl_context_activate (GstGLContext * context, gboolean activate)
742 {
743   GstGLContextClass *context_class;
744   gboolean result;
745 
746   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
747   context_class = GST_GL_CONTEXT_GET_CLASS (context);
748   g_return_val_if_fail (context_class->activate != NULL, FALSE);
749 
750   GST_DEBUG_OBJECT (context, "activate:%d", activate);
751 
752   GST_OBJECT_LOCK (context);
753   result = context_class->activate (context, activate);
754 
755   if (result && activate) {
756     GThread *old_thread = context->priv->active_thread;
757     context->priv->active_thread = g_thread_ref (g_thread_self ());
758     if (old_thread) {
759       g_thread_unref (old_thread);
760     }
761 
762     g_private_set (&current_context_key, context);
763   } else {
764     if (context->priv->active_thread) {
765       g_thread_unref (context->priv->active_thread);
766       context->priv->active_thread = NULL;
767     }
768     g_private_set (&current_context_key, NULL);
769   }
770   GST_OBJECT_UNLOCK (context);
771 
772   return result;
773 }
774 
775 /**
776  * gst_gl_context_get_thread:
777  * @context: a #GstGLContext
778  *
779  * Returns: (transfer full): The #GThread, @context is current in or NULL
780  *
781  * Since: 1.6
782  */
783 GThread *
gst_gl_context_get_thread(GstGLContext * context)784 gst_gl_context_get_thread (GstGLContext * context)
785 {
786   GThread *ret;
787 
788   GST_OBJECT_LOCK (context);
789   ret = context->priv->active_thread;
790   if (ret)
791     g_thread_ref (ret);
792   GST_OBJECT_UNLOCK (context);
793 
794   return ret;
795 }
796 
797 /**
798  * gst_gl_context_get_gl_api:
799  * @context: a #GstGLContext
800  *
801  * Get the currently enabled OpenGL api.
802  *
803  * The currently available API may be limited by the #GstGLDisplay in use and/or
804  * the #GstGLWindow chosen.
805  *
806  * Returns: the available OpenGL api
807  *
808  * Since: 1.4
809  */
810 GstGLAPI
gst_gl_context_get_gl_api(GstGLContext * context)811 gst_gl_context_get_gl_api (GstGLContext * context)
812 {
813   GstGLContextClass *context_class;
814 
815   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), GST_GL_API_NONE);
816   context_class = GST_GL_CONTEXT_GET_CLASS (context);
817   g_return_val_if_fail (context_class->get_gl_api != NULL, GST_GL_API_NONE);
818 
819   return context_class->get_gl_api (context);
820 }
821 
822 /**
823  * gst_gl_context_get_proc_address:
824  * @context: a #GstGLContext
825  * @name: an opengl function name
826  *
827  * Get a function pointer to a specified opengl function, @name.  If the the
828  * specific function does not exist, NULL is returned instead.
829  *
830  * Platform specfic functions (names starting 'egl', 'glX', 'wgl', etc) can also
831  * be retrieved using this method.
832  *
833  * Note: This function may return valid function pointers that may not be valid
834  * to call in @context.  The caller is responsible for ensuring that the
835  * returned function is a valid function to call in @context by either checking
836  * the OpenGL API and version or for an appropriate OpenGL extension.
837  *
838  * Note: On success, you need to cast the returned function pointer to the
839  * correct type to be able to call it correctly.  On 32-bit Windows, this will
840  * include the %GSTGLAPI identifier to use the correct calling convention.
841  * e.g.
842  *
843  * |[<!-- language="C" -->
844  * void (GSTGLAPI *PFN_glGetIntegerv) (GLenum name, GLint * ret)
845  * ]|
846  *
847  * Returns: a function pointer or %NULL
848  *
849  * Since: 1.4
850  */
851 gpointer
gst_gl_context_get_proc_address(GstGLContext * context,const gchar * name)852 gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
853 {
854   gpointer ret;
855   GstGLContextClass *context_class;
856   GstGLAPI gl_api;
857 
858   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
859   context_class = GST_GL_CONTEXT_GET_CLASS (context);
860   g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);
861 
862   gl_api = gst_gl_context_get_gl_api (context);
863   ret = context_class->get_proc_address (gl_api, name);
864 
865   return ret;
866 }
867 
868 /**
869  * gst_gl_context_default_get_proc_address:
870  * @gl_api: a #GstGLAPI
871  * @name: then function to get the address of
872  *
873  * A default implementation of the various GetProcAddress functions that looks
874  * for @name in the OpenGL shared libraries or in the current process.
875  *
876  * See also: gst_gl_context_get_proc_address()
877  *
878  * Returns: an address pointing to @name or %NULL
879  *
880  * Since: 1.4
881  */
882 gpointer
gst_gl_context_default_get_proc_address(GstGLAPI gl_api,const gchar * name)883 gst_gl_context_default_get_proc_address (GstGLAPI gl_api, const gchar * name)
884 {
885   gpointer ret = NULL;
886 
887   /* First try to load symbol from the selected GL API for this context */
888 #if GST_GL_HAVE_GLES2
889   if (!ret && (gl_api & GST_GL_API_GLES2)) {
890     g_once (&module_gles2_gonce, load_gles2_module, NULL);
891     if (module_gles2)
892       g_module_symbol (module_gles2, name, &ret);
893   }
894 #endif
895 
896 #if GST_GL_HAVE_OPENGL
897   if (!ret && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
898     g_once (&module_opengl_gonce, load_opengl_module, NULL);
899     if (module_opengl)
900       g_module_symbol (module_opengl, name, &ret);
901   }
902 #endif
903 
904   /* Otherwise fall back to the current module */
905   g_once (&module_self_gonce, load_self_module, NULL);
906   if (!ret)
907     g_module_symbol (module_self, name, &ret);
908 
909   return ret;
910 }
911 
912 /**
913  * gst_gl_context_set_window:
914  * @context: a #GstGLContext
915  * @window: (transfer full): a #GstGLWindow
916  *
917  * Set's the current window on @context to @window.  The window can only be
918  * changed before gst_gl_context_create() has been called and the @window is not
919  * already running.
920  *
921  * Returns: Whether the window was successfully updated
922  *
923  * Since: 1.4
924  */
925 gboolean
gst_gl_context_set_window(GstGLContext * context,GstGLWindow * window)926 gst_gl_context_set_window (GstGLContext * context, GstGLWindow * window)
927 {
928   g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
929 
930   GST_DEBUG_OBJECT (context, "window:%" GST_PTR_FORMAT, window);
931 
932   /* we can't change the window while we are running */
933   if (context->priv->alive)
934     return FALSE;
935 
936   if (window)
937     g_weak_ref_set (&window->context_ref, context);
938 
939   if (context->window)
940     gst_object_unref (context->window);
941 
942   context->window = window ? gst_object_ref (window) : NULL;
943 
944   return TRUE;
945 }
946 
947 /**
948  * gst_gl_context_get_window:
949  * @context: a #GstGLContext
950  *
951  * Returns: (transfer full) (nullable): the currently set window
952  *
953  * Since: 1.4
954  */
955 GstGLWindow *
gst_gl_context_get_window(GstGLContext * context)956 gst_gl_context_get_window (GstGLContext * context)
957 {
958   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
959 
960   if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
961     GST_WARNING_OBJECT (context, "context is not toplevel, returning NULL");
962     return NULL;
963   }
964 
965   _ensure_window (context);
966 
967   return gst_object_ref (context->window);
968 }
969 
970 /**
971  * gst_gl_context_can_share:
972  * @context: a #GstGLContext
973  * @other_context: another #GstGLContext
974  *
975  * Note: This will always fail for two wrapped #GstGLContext's
976  *
977  * Returns: whether @context and @other_context are able to share OpenGL
978  *      resources.
979  *
980  * Since: 1.6
981  */
982 gboolean
gst_gl_context_can_share(GstGLContext * context,GstGLContext * other_context)983 gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
984 {
985   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
986   g_return_val_if_fail (GST_IS_GL_CONTEXT (other_context), FALSE);
987 
988   /* check if the contexts are descendants or the root nodes are the same */
989   return context->priv->sharegroup != NULL
990       && context->priv->sharegroup == other_context->priv->sharegroup;
991 }
992 
993 /**
994  * gst_gl_context_create:
995  * @context: a #GstGLContext:
996  * @other_context: (allow-none): a #GstGLContext to share OpenGL objects with
997  * @error: (allow-none): a #GError
998  *
999  * Creates an OpenGL context with the specified @other_context as a context
1000  * to share shareable OpenGL objects with.  See the OpenGL specification for
1001  * what is shared between OpenGL contexts.
1002  *
1003  * If an error occurs, and @error is not %NULL, then error will contain details
1004  * of the error and %FALSE will be returned.
1005  *
1006  * Should only be called once.
1007  *
1008  * Returns: whether the context could successfully be created
1009  *
1010  * Since: 1.4
1011  */
1012 gboolean
gst_gl_context_create(GstGLContext * context,GstGLContext * other_context,GError ** error)1013 gst_gl_context_create (GstGLContext * context,
1014     GstGLContext * other_context, GError ** error)
1015 {
1016   gboolean alive = FALSE;
1017 
1018   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1019   g_return_val_if_fail (!GST_IS_GL_WRAPPED_CONTEXT (context), FALSE);
1020 
1021   GST_DEBUG_OBJECT (context, " other_context:%" GST_PTR_FORMAT, other_context);
1022 
1023   _ensure_window (context);
1024 
1025   g_mutex_lock (&context->priv->render_lock);
1026 
1027   if (!context->priv->created) {
1028     g_weak_ref_set (&context->priv->other_context_ref, other_context);
1029     context->priv->error = error;
1030     if (other_context == NULL)
1031       context->priv->sharegroup = _context_share_group_new ();
1032     else
1033       context->priv->sharegroup =
1034           _context_share_group_ref (other_context->priv->sharegroup);
1035 
1036     context->priv->gl_thread = g_thread_new ("gstglcontext",
1037         (GThreadFunc) gst_gl_context_create_thread, context);
1038 
1039     while (!context->priv->created)
1040       g_cond_wait (&context->priv->create_cond, &context->priv->render_lock);
1041 
1042     GST_INFO_OBJECT (context, "gl thread created");
1043   }
1044 
1045   alive = context->priv->alive;
1046 
1047   g_mutex_unlock (&context->priv->render_lock);
1048 
1049   return alive;
1050 }
1051 
1052 static gboolean
_create_context_info(GstGLContext * context,GstGLAPI gl_api,gint * gl_major,gint * gl_minor,GError ** error)1053 _create_context_info (GstGLContext * context, GstGLAPI gl_api, gint * gl_major,
1054     gint * gl_minor, GError ** error)
1055 {
1056   const GstGLFuncs *gl;
1057   guint maj = 0, min = 0;
1058   GLenum gl_err = GL_NO_ERROR;
1059   const gchar *opengl_version = NULL;
1060 
1061   gl = context->gl_vtable;
1062 
1063   if (!gl->GetString || !gl->GetString (GL_VERSION)) {
1064     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1065         "glGetString not defined or returned invalid value");
1066     return FALSE;
1067   }
1068 
1069   if (!gl->GetString (GL_SHADING_LANGUAGE_VERSION)) {
1070     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1071         "No GL shader support available");
1072     return FALSE;
1073   }
1074 
1075   GST_INFO_OBJECT (context, "GL_VERSION: %s",
1076       GST_STR_NULL ((const gchar *) gl->GetString (GL_VERSION)));
1077   GST_INFO_OBJECT (context, "GL_SHADING_LANGUAGE_VERSION: %s",
1078       GST_STR_NULL ((const gchar *)
1079           gl->GetString (GL_SHADING_LANGUAGE_VERSION)));
1080   GST_INFO_OBJECT (context, "GL_VENDOR: %s",
1081       GST_STR_NULL ((const gchar *) gl->GetString (GL_VENDOR)));
1082   GST_INFO_OBJECT (context, "GL_RENDERER: %s",
1083       GST_STR_NULL ((const gchar *) gl->GetString (GL_RENDERER)));
1084 
1085   gl_err = gl->GetError ();
1086   if (gl_err != GL_NO_ERROR) {
1087     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1088         "glGetString error: 0x%x", gl_err);
1089     return FALSE;
1090   }
1091 
1092   opengl_version = (const gchar *) gl->GetString (GL_VERSION);
1093   if (opengl_version && gl_api & GST_GL_API_GLES2)
1094     /* gles starts with "OpenGL ES " */
1095     opengl_version = &opengl_version[10];
1096 
1097   if (opengl_version)
1098     sscanf (opengl_version, "%d.%d", &maj, &min);
1099 
1100   /* OpenGL > 1.2.0 */
1101   if (gl_api & GST_GL_API_OPENGL || gl_api & GST_GL_API_OPENGL3) {
1102     if ((maj < 1) || (maj < 2 && maj >= 1 && min < 2)) {
1103       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS,
1104           "OpenGL >= 1.2.0 required, found %u.%u", maj, min);
1105       return FALSE;
1106     }
1107   }
1108 
1109   if (gl_major)
1110     *gl_major = maj;
1111   if (gl_minor)
1112     *gl_minor = min;
1113 
1114   return TRUE;
1115 }
1116 
1117 static GstGLAPI
_compiled_api(void)1118 _compiled_api (void)
1119 {
1120   GstGLAPI ret = GST_GL_API_NONE;
1121 
1122 #if GST_GL_HAVE_OPENGL
1123   ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
1124 #endif
1125 #if GST_GL_HAVE_GLES2
1126   ret |= GST_GL_API_GLES2;
1127 #endif
1128 
1129   return ret;
1130 }
1131 
1132 static void
_unlock_create_thread(GstGLContext * context)1133 _unlock_create_thread (GstGLContext * context)
1134 {
1135   context->priv->created = TRUE;
1136   GST_INFO_OBJECT (context, "gl thread running");
1137   g_cond_signal (&context->priv->create_cond);
1138   g_mutex_unlock (&context->priv->render_lock);
1139 }
1140 
1141 static GString *
_build_extension_string(GstGLContext * context)1142 _build_extension_string (GstGLContext * context)
1143 {
1144   const GstGLFuncs *gl = context->gl_vtable;
1145   GString *ext_g_str = g_string_sized_new (1024);
1146   const gchar *ext_const_c_str = NULL;
1147   GLint i = 0;
1148   GLint n = 0;
1149 
1150   gl->GetIntegerv (GL_NUM_EXTENSIONS, &n);
1151 
1152   for (i = 0; i < n; i++) {
1153     ext_const_c_str = (const gchar *) gl->GetStringi (GL_EXTENSIONS, i);
1154     if (ext_const_c_str)
1155       g_string_append_printf (ext_g_str, "%s ", ext_const_c_str);
1156   }
1157 
1158   return ext_g_str;
1159 }
1160 
1161 //gboolean
1162 //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error)
1163 static gpointer
gst_gl_context_create_thread(GstGLContext * context)1164 gst_gl_context_create_thread (GstGLContext * context)
1165 {
1166   GstGLContextClass *context_class;
1167   GstGLWindowClass *window_class;
1168   GstGLAPI compiled_api, user_api, gl_api, display_api;
1169   gchar *api_string;
1170   gchar *compiled_api_s;
1171   gchar *user_api_s;
1172   gchar *display_api_s;
1173   const gchar *user_choice;
1174   GError **error;
1175   GstGLContext *other_context;
1176 
1177   g_mutex_lock (&context->priv->render_lock);
1178 
1179   GST_DEBUG_OBJECT (context, "Creating thread");
1180 
1181   error = context->priv->error;
1182   other_context = g_weak_ref_get (&context->priv->other_context_ref);
1183 
1184   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1185   window_class = GST_GL_WINDOW_GET_CLASS (context->window);
1186 
1187   display_api = gst_gl_display_get_gl_api_unlocked (context->display);
1188   if (display_api == GST_GL_API_NONE) {
1189     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1190         "Cannot create context with satisfying requested apis "
1191         "(display has no GL api!)");
1192     goto failure;
1193   }
1194 
1195   if (window_class->open) {
1196     if (!window_class->open (context->window, error)) {
1197       GST_WARNING_OBJECT (context, "Failed to open window");
1198       g_assert (error == NULL || *error != NULL);
1199       goto failure;
1200     }
1201   }
1202 
1203   compiled_api = _compiled_api ();
1204   compiled_api_s = gst_gl_api_to_string (compiled_api);
1205 
1206   user_choice = g_getenv ("GST_GL_API");
1207   user_api = gst_gl_api_from_string (user_choice);
1208   user_api_s = gst_gl_api_to_string (user_api);
1209 
1210   display_api_s = gst_gl_api_to_string (display_api);
1211 
1212   if ((user_api & compiled_api & display_api) == GST_GL_API_NONE) {
1213     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1214         "Cannot create context with the user requested api (%s).  "
1215         "We have support for (%s), display api (%s)", user_api_s,
1216         compiled_api_s, display_api_s);
1217     g_free (user_api_s);
1218     g_free (compiled_api_s);
1219     g_free (display_api_s);
1220     goto failure;
1221   }
1222 
1223   if (context_class->choose_format &&
1224       !context_class->choose_format (context, error)) {
1225     GST_WARNING_OBJECT (context, "Failed to choose format");
1226     g_assert (error == NULL || *error != NULL);
1227     g_free (compiled_api_s);
1228     g_free (user_api_s);
1229     g_free (display_api_s);
1230     goto failure;
1231   }
1232 
1233   GST_INFO_OBJECT (context,
1234       "Attempting to create opengl context. user chosen api(s) (%s), "
1235       "compiled api support (%s) display api (%s)", user_api_s, compiled_api_s,
1236       display_api_s);
1237 
1238   if (!context_class->create_context (context,
1239           compiled_api & user_api & display_api, other_context, error)) {
1240     GST_WARNING_OBJECT (context, "Failed to create context");
1241     g_assert (error == NULL || *error != NULL);
1242     g_free (compiled_api_s);
1243     g_free (user_api_s);
1244     g_free (display_api_s);
1245     goto failure;
1246   }
1247   GST_INFO_OBJECT (context, "created context");
1248 
1249   if (!gst_gl_context_activate (context, TRUE)) {
1250     g_set_error (error, GST_GL_CONTEXT_ERROR,
1251         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
1252         "Failed to activate the GL Context");
1253     g_free (compiled_api_s);
1254     g_free (user_api_s);
1255     g_free (display_api_s);
1256     goto failure;
1257   }
1258 
1259   gl_api = gst_gl_context_get_gl_api (context);
1260   g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY);
1261 
1262   api_string = gst_gl_api_to_string (gl_api);
1263   GST_INFO_OBJECT (context, "available GL APIs: %s", api_string);
1264 
1265   if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) {
1266     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
1267         "failed to create context, context "
1268         "could not provide correct api. user (%s), compiled (%s), context (%s)",
1269         user_api_s, compiled_api_s, api_string);
1270     g_free (api_string);
1271     g_free (compiled_api_s);
1272     g_free (user_api_s);
1273     g_free (display_api_s);
1274     goto failure;
1275   }
1276 
1277   g_free (api_string);
1278   g_free (compiled_api_s);
1279   g_free (user_api_s);
1280   g_free (display_api_s);
1281 
1282   GST_DEBUG_OBJECT (context, "Filling info");
1283   if (!gst_gl_context_fill_info (context, error)) {
1284     g_assert (error == NULL || *error != NULL);
1285     goto failure;
1286   }
1287 
1288   context->priv->alive = TRUE;
1289 
1290 #if !defined(GST_DISABLE_GST_DEBUG)
1291   _gst_gl_debug_enable (context);
1292 #endif
1293 
1294   if (other_context) {
1295     GST_DEBUG_OBJECT (context, "Unreffing other_context %" GST_PTR_FORMAT,
1296         other_context);
1297     gst_object_unref (other_context);
1298   }
1299 
1300   /* unlocking of the render_lock happens when the
1301    * context's loop is running from inside that loop */
1302   gst_gl_window_send_message_async (context->window,
1303       (GstGLWindowCB) _unlock_create_thread, context, NULL);
1304 
1305   gst_gl_window_run (context->window);
1306 
1307   GST_INFO_OBJECT (context, "loop exited");
1308 
1309   g_mutex_lock (&context->priv->render_lock);
1310   context->priv->alive = FALSE;
1311 
1312   gst_gl_context_activate (context, FALSE);
1313 
1314   context_class->destroy_context (context);
1315 
1316   /* User supplied callback */
1317   if (context->window->close)
1318     context->window->close (context->window->close_data);
1319 
1320   /* window specific shutdown */
1321   if (window_class->close) {
1322     window_class->close (context->window);
1323   }
1324 
1325   context->priv->created = FALSE;
1326   g_cond_signal (&context->priv->destroy_cond);
1327   g_mutex_unlock (&context->priv->render_lock);
1328 
1329   return NULL;
1330 
1331 failure:
1332   {
1333     if (other_context)
1334       gst_object_unref (other_context);
1335 
1336     /* A context that fails to be created is considered created but not alive
1337      * and will never be able to be alive as creation can't happen */
1338     context->priv->created = TRUE;
1339     g_cond_signal (&context->priv->create_cond);
1340     g_mutex_unlock (&context->priv->render_lock);
1341     return NULL;
1342   }
1343 }
1344 
1345 /**
1346  * gst_gl_context_destroy:
1347  * @context: a #GstGLContext:
1348  *
1349  * Destroys an OpenGL context.
1350  *
1351  * Should only be called after gst_gl_context_create() has been successfully
1352  * called for this context.
1353  *
1354  * Since: 1.6
1355  */
1356 void
gst_gl_context_destroy(GstGLContext * context)1357 gst_gl_context_destroy (GstGLContext * context)
1358 {
1359   GstGLContextClass *context_class;
1360 
1361   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1362   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1363   g_return_if_fail (context_class->destroy_context != NULL);
1364 
1365   context_class->destroy_context (context);
1366 }
1367 
1368 /**
1369  * gst_gl_context_fill_info:
1370  * @context: a #GstGLContext:
1371  * @error: (allow-none): a #GError to fill on failure
1372  *
1373  * Fills @context's info (version, extensions, vtable, etc) from the GL
1374  * context in the current thread.  Typically used with wrapped contexts to
1375  * allow wrapped contexts to be used as regular #GstGLContext's.
1376  *
1377  * Since: 1.6
1378  */
1379 gboolean
gst_gl_context_fill_info(GstGLContext * context,GError ** error)1380 gst_gl_context_fill_info (GstGLContext * context, GError ** error)
1381 {
1382   GstGLFuncs *gl;
1383   GString *ext_g_str = NULL;
1384   const gchar *ext_const_c_str = NULL;
1385   GstGLAPI gl_api;
1386   gboolean ret;
1387 
1388   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1389   g_return_val_if_fail (context->priv->active_thread == g_thread_self (),
1390       FALSE);
1391 
1392   gl = context->gl_vtable;
1393   gl_api = gst_gl_context_get_gl_api (context);
1394 
1395   gl->GetError = gst_gl_context_get_proc_address (context, "glGetError");
1396   gl->GetString = gst_gl_context_get_proc_address (context, "glGetString");
1397   gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi");
1398   gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv");
1399 
1400   if (!gl->GetError || !gl->GetString) {
1401     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1402         "could not GetProcAddress core opengl functions");
1403     goto failure;
1404   }
1405 
1406   /* gl api specific code */
1407   ret = _create_context_info (context, gl_api, &context->priv->gl_major,
1408       &context->priv->gl_minor, error);
1409 
1410   if (!ret) {
1411     g_assert (error == NULL || *error != NULL);
1412     goto failure;
1413   }
1414 
1415   /* GL core contexts and GLES3 */
1416   if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3)
1417     ext_g_str = _build_extension_string (context);
1418 
1419   if (ext_g_str && ext_g_str->len) {
1420     GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str);
1421     _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1422         context->priv->gl_minor, ext_g_str->str);
1423 
1424     context->priv->gl_exts = g_string_free (ext_g_str, FALSE);
1425   } else {
1426     ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS);
1427     if (!ext_const_c_str)
1428       ext_const_c_str = "";
1429 
1430     GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str);
1431     _gst_gl_feature_check_ext_functions (context, context->priv->gl_major,
1432         context->priv->gl_minor, ext_const_c_str);
1433 
1434     context->priv->gl_exts = g_strdup (ext_const_c_str);
1435   }
1436 
1437   if (gl_api & GST_GL_API_OPENGL3
1438       && !gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 4, 1)
1439       && !gst_gl_check_extension ("GL_ARB_ES2_compatibility",
1440           context->priv->gl_exts)) {
1441     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1442         "An opengl3 context created but the required ES2 compatibility was not found");
1443     goto failure;
1444   }
1445 
1446   /* Does not implement OES_vertex_array_object properly, see
1447    * https://bugzilla.gnome.org/show_bug.cgi?id=750185 */
1448   if (g_strcmp0 ((const gchar *) gl->GetString (GL_VENDOR),
1449           "Imagination Technologies") == 0
1450       && g_strcmp0 ((const gchar *) gl->GetString (GL_RENDERER),
1451           "PowerVR SGX 544MP") == 0) {
1452     gl->GenVertexArrays = NULL;
1453     gl->DeleteVertexArrays = NULL;
1454     gl->BindVertexArray = NULL;
1455     gl->IsVertexArray = NULL;
1456   }
1457 
1458   return TRUE;
1459 
1460 failure:
1461   return FALSE;
1462 }
1463 
1464 /**
1465  * gst_gl_context_get_gl_context:
1466  * @context: a #GstGLContext:
1467  *
1468  * Gets the backing OpenGL context used by @context.
1469  *
1470  * Returns: The platform specific backing OpenGL context
1471  *
1472  * Since: 1.4
1473  */
1474 guintptr
gst_gl_context_get_gl_context(GstGLContext * context)1475 gst_gl_context_get_gl_context (GstGLContext * context)
1476 {
1477   GstGLContextClass *context_class;
1478   guintptr result;
1479 
1480   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1481   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1482   g_return_val_if_fail (context_class->get_gl_context != NULL, 0);
1483 
1484   result = context_class->get_gl_context (context);
1485 
1486   return result;
1487 }
1488 
1489 /**
1490  * gst_gl_context_get_gl_platform:
1491  * @context: a #GstGLContext:
1492  *
1493  * Gets the OpenGL platform that used by @context.
1494  *
1495  * Returns: The platform specific backing OpenGL context
1496  *
1497  * Since: 1.4
1498  */
1499 GstGLPlatform
gst_gl_context_get_gl_platform(GstGLContext * context)1500 gst_gl_context_get_gl_platform (GstGLContext * context)
1501 {
1502   GstGLContextClass *context_class;
1503 
1504   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), 0);
1505   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1506   g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);
1507 
1508   return context_class->get_gl_platform (context);
1509 }
1510 
1511 /**
1512  * gst_gl_context_get_display:
1513  * @context: a #GstGLContext:
1514  *
1515  * Returns: (transfer full): the #GstGLDisplay associated with this @context
1516  *
1517  * Since: 1.4
1518  */
1519 GstGLDisplay *
gst_gl_context_get_display(GstGLContext * context)1520 gst_gl_context_get_display (GstGLContext * context)
1521 {
1522   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
1523 
1524   return gst_object_ref (context->display);
1525 }
1526 
1527 typedef struct
1528 {
1529   GstGLContext *context;
1530   GstGLContextThreadFunc func;
1531   gpointer data;
1532 } RunGenericData;
1533 
1534 static void
_gst_gl_context_thread_run_generic(RunGenericData * data)1535 _gst_gl_context_thread_run_generic (RunGenericData * data)
1536 {
1537   GST_TRACE_OBJECT (data->context, "running function:%p data:%p", data->func,
1538       data->data);
1539 
1540   data->func (data->context, data->data);
1541 }
1542 
1543 /**
1544  * gst_gl_context_thread_add:
1545  * @context: a #GstGLContext
1546  * @func: (scope call): a #GstGLContextThreadFunc
1547  * @data: (closure): user data to call @func with
1548  *
1549  * Execute @func in the OpenGL thread of @context with @data
1550  *
1551  * MT-safe
1552  *
1553  * Since: 1.4
1554  */
1555 void
gst_gl_context_thread_add(GstGLContext * context,GstGLContextThreadFunc func,gpointer data)1556 gst_gl_context_thread_add (GstGLContext * context,
1557     GstGLContextThreadFunc func, gpointer data)
1558 {
1559   GstGLWindow *window;
1560   RunGenericData rdata;
1561 
1562   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1563   g_return_if_fail (func != NULL);
1564 
1565   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1566     g_return_if_fail (context->priv->active_thread == g_thread_self ());
1567 
1568   if (context->priv->active_thread == g_thread_self ()) {
1569     func (context, data);
1570     return;
1571   }
1572 
1573   rdata.context = context;
1574   rdata.data = data;
1575   rdata.func = func;
1576 
1577   window = gst_gl_context_get_window (context);
1578 
1579   gst_gl_window_send_message (window,
1580       GST_GL_WINDOW_CB (_gst_gl_context_thread_run_generic), &rdata);
1581 
1582   gst_object_unref (window);
1583 }
1584 
1585 /**
1586  * gst_gl_context_get_gl_version:
1587  * @context: a #GstGLContext
1588  * @maj: (out): resulting major version
1589  * @min: (out): resulting minor version
1590  *
1591  * Returns the OpenGL version implemented by @context.  See
1592  * gst_gl_context_get_gl_api() for retreiving the OpenGL api implemented by
1593  * @context.
1594  *
1595  * Since: 1.4
1596  */
1597 void
gst_gl_context_get_gl_version(GstGLContext * context,gint * maj,gint * min)1598 gst_gl_context_get_gl_version (GstGLContext * context, gint * maj, gint * min)
1599 {
1600   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1601   g_return_if_fail (!(maj == NULL && min == NULL));
1602 
1603   if (maj)
1604     *maj = context->priv->gl_major;
1605 
1606   if (min)
1607     *min = context->priv->gl_minor;
1608 }
1609 
1610 /**
1611  * gst_gl_context_check_gl_version:
1612  * @context: a #GstGLContext
1613  * @api: api type required
1614  * @maj: major version required
1615  * @min: minor version required
1616  *
1617  * Returns: whether OpenGL context implements the required api and specified
1618  * version.
1619  *
1620  * Since: 1.4
1621  */
1622 gboolean
gst_gl_context_check_gl_version(GstGLContext * context,GstGLAPI api,gint maj,gint min)1623 gst_gl_context_check_gl_version (GstGLContext * context, GstGLAPI api,
1624     gint maj, gint min)
1625 {
1626   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1627 
1628   if (maj > context->priv->gl_major)
1629     return FALSE;
1630 
1631   if ((gst_gl_context_get_gl_api (context) & api) == GST_GL_API_NONE)
1632     return FALSE;
1633 
1634   if (maj < context->priv->gl_major)
1635     return TRUE;
1636 
1637   if (min > context->priv->gl_minor)
1638     return FALSE;
1639 
1640   return TRUE;
1641 }
1642 
1643 /**
1644  * gst_gl_context_check_feature:
1645  * @context: a #GstGLContext
1646  * @feature: a platform specific feature
1647  *
1648  * Check for an OpenGL @feature being supported.
1649  *
1650  * Note: Most features require that the context be created before it is
1651  * possible to determine their existence and so will fail if that is not the
1652  * case.
1653  *
1654  * Returns: Whether @feature is supported by @context
1655  *
1656  * Since: 1.4
1657  */
1658 gboolean
gst_gl_context_check_feature(GstGLContext * context,const gchar * feature)1659 gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
1660 {
1661   GstGLContextClass *context_class;
1662 
1663   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1664   g_return_val_if_fail (feature != NULL, FALSE);
1665 
1666   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1667 
1668   if (g_strstr_len (feature, 3, "GL_"))
1669     return gst_gl_check_extension (feature, context->priv->gl_exts);
1670 
1671   if (!context_class->check_feature)
1672     return FALSE;
1673 
1674   return context_class->check_feature (context, feature);
1675 }
1676 
1677 /**
1678  * gst_gl_context_get_current:
1679  *
1680  * See also gst_gl_context_activate().
1681  *
1682  * Returns: (transfer none): the #GstGLContext active in the current thread or %NULL
1683  *
1684  * Since: 1.6
1685  */
1686 GstGLContext *
gst_gl_context_get_current(void)1687 gst_gl_context_get_current (void)
1688 {
1689   return g_private_get (&current_context_key);
1690 }
1691 
1692 /**
1693  * gst_gl_context_is_shared:
1694  * @context: a #GstGLContext
1695  *
1696  * Returns: Whether the #GstGLContext has been shared with another #GstGLContext
1697  *
1698  * Since: 1.8
1699  */
1700 gboolean
gst_gl_context_is_shared(GstGLContext * context)1701 gst_gl_context_is_shared (GstGLContext * context)
1702 {
1703   g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
1704 
1705   if (!context->priv->sharegroup)
1706     return FALSE;
1707 
1708   if (GST_IS_GL_WRAPPED_CONTEXT (context))
1709     g_return_val_if_fail (context->priv->active_thread, FALSE);
1710   else
1711     g_return_val_if_fail (context->priv->alive, FALSE);
1712 
1713   return _context_share_group_is_shared (context->priv->sharegroup);
1714 }
1715 
1716 /**
1717  * gst_gl_context_set_shared_with:
1718  * @context: a wrapped #GstGLContext
1719  * @share: another #GstGLContext
1720  *
1721  * Will internally set @context as shared with @share
1722  *
1723  * Since: 1.8
1724  */
1725 void
gst_gl_context_set_shared_with(GstGLContext * context,GstGLContext * share)1726 gst_gl_context_set_shared_with (GstGLContext * context, GstGLContext * share)
1727 {
1728   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1729   g_return_if_fail (GST_IS_GL_CONTEXT (share));
1730   g_return_if_fail (!gst_gl_context_is_shared (context));
1731   /* XXX: may be a little too strict */
1732   g_return_if_fail (GST_IS_GL_WRAPPED_CONTEXT (context));
1733 
1734   if (context->priv->sharegroup)
1735     _context_share_group_unref (context->priv->sharegroup);
1736   context->priv->sharegroup =
1737       _context_share_group_ref (share->priv->sharegroup);
1738 }
1739 
1740 static void
gst_gl_context_default_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)1741 gst_gl_context_default_get_gl_platform_version (GstGLContext * context,
1742     gint * major, gint * minor)
1743 {
1744   if (major)
1745     *major = 0;
1746   if (minor)
1747     *minor = 0;
1748 }
1749 
1750 /**
1751  * gst_gl_context_get_gl_platform_version:
1752  * @context: a #GstGLContext
1753  * @major: (out): return for the major version
1754  * @minor: (out): return for the minor version
1755  *
1756  * Get the version of the OpenGL platform (GLX, EGL, etc) used.  Only valid
1757  * after a call to gst_gl_context_create().
1758  */
1759 void
gst_gl_context_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)1760 gst_gl_context_get_gl_platform_version (GstGLContext * context, gint * major,
1761     gint * minor)
1762 {
1763   GstGLContextClass *context_class;
1764 
1765   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1766   g_return_if_fail (major != NULL);
1767   g_return_if_fail (minor != NULL);
1768   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1769   g_return_if_fail (context_class->get_gl_platform_version != NULL);
1770 
1771   context_class->get_gl_platform_version (context, major, minor);
1772 }
1773 
1774 /**
1775  * gst_gl_context_swap_buffers:
1776  * @context: a #GstGLContext
1777  *
1778  * Swap the front and back buffers on the window attached to @context.
1779  * This will display the frame on the next refresh cycle.
1780  */
1781 void
gst_gl_context_swap_buffers(GstGLContext * context)1782 gst_gl_context_swap_buffers (GstGLContext * context)
1783 {
1784   GstGLContextClass *context_class;
1785 
1786   g_return_if_fail (GST_IS_GL_CONTEXT (context));
1787   context_class = GST_GL_CONTEXT_GET_CLASS (context);
1788   g_return_if_fail (context_class->swap_buffers != NULL);
1789 
1790   context_class->swap_buffers (context);
1791 }
1792 
1793 static GstGLAPI
gst_gl_wrapped_context_get_gl_api(GstGLContext * context)1794 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
1795 {
1796   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1797 
1798   return context_wrap->available_apis;
1799 }
1800 
1801 static guintptr
gst_gl_wrapped_context_get_gl_context(GstGLContext * context)1802 gst_gl_wrapped_context_get_gl_context (GstGLContext * context)
1803 {
1804   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1805 
1806   return context_wrap->handle;
1807 }
1808 
1809 static GstGLPlatform
gst_gl_wrapped_context_get_gl_platform(GstGLContext * context)1810 gst_gl_wrapped_context_get_gl_platform (GstGLContext * context)
1811 {
1812   GstGLWrappedContext *context_wrap = GST_GL_WRAPPED_CONTEXT (context);
1813 
1814   return context_wrap->platform;
1815 }
1816 
1817 static gboolean
gst_gl_wrapped_context_activate(GstGLContext * context,gboolean activate)1818 gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
1819 {
1820   if (activate) {
1821     GThread *old_thread = context->priv->gl_thread;
1822     context->priv->gl_thread = g_thread_ref (g_thread_self ());
1823     if (old_thread) {
1824       g_thread_unref (old_thread);
1825     }
1826   } else {
1827     if (context->priv->gl_thread) {
1828       g_thread_unref (context->priv->gl_thread);
1829       context->priv->gl_thread = NULL;
1830     }
1831   }
1832 
1833   return TRUE;
1834 }
1835 
1836 static void
gst_gl_wrapped_context_class_init(GstGLWrappedContextClass * klass)1837 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
1838 {
1839   GstGLContextClass *context_class = (GstGLContextClass *) klass;
1840 
1841   context_class->get_gl_context =
1842       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_context);
1843   context_class->get_gl_api =
1844       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_api);
1845   context_class->get_gl_platform =
1846       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
1847   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
1848 }
1849 
1850 static void
gst_gl_wrapped_context_init(GstGLWrappedContext * context)1851 gst_gl_wrapped_context_init (GstGLWrappedContext * context)
1852 {
1853 }
1854 
1855 G_GNUC_INTERNAL gboolean
_gst_gl_context_debug_is_enabled(GstGLContext * context)1856 _gst_gl_context_debug_is_enabled (GstGLContext * context)
1857 {
1858 #if !defined(GST_DISABLE_GST_DEBUG)
1859   GstDebugLevel level;
1860 
1861   level = gst_debug_category_get_threshold (gst_gl_debug);
1862 
1863   if (level < GST_LEVEL_WARNING) {
1864     GST_CAT_INFO_OBJECT (gst_gl_context_debug, context, "Disabling GL context "
1865         "debugging (gldebug category debug level < warning)");
1866     return FALSE;
1867   }
1868   return TRUE;
1869 #else
1870   return FALSE;
1871 #endif
1872 }
1873