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 (¤t_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 (¤t_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 (¤t_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