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