• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2013 Sebastian Dröge <slomo@circular-chaos.org>
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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <gmodule.h>
26 
27 /* FIXME: Sharing contexts requires the EGLDisplay to be the same
28  * may need to box it.
29  */
30 
31 #include "gstglcontext_egl.h"
32 
33 #include <gst/gl/gl.h>
34 #include <gst/gl/gstglcontext_private.h>
35 
36 #include "gstegl.h"
37 #include "../utils/opengl_versions.h"
38 #include "../utils/gles_versions.h"
39 
40 #if GST_GL_HAVE_WINDOW_X11
41 #include "../x11/gstglwindow_x11.h"
42 #include <gst/gl/x11/gstgldisplay_x11.h>
43 #endif
44 #if GST_GL_HAVE_WINDOW_WAYLAND
45 #include "../wayland/gstglwindow_wayland_egl.h"
46 #endif
47 #if GST_GL_HAVE_WINDOW_WIN32
48 #include "../win32/gstglwindow_win32.h"
49 #endif
50 #if GST_GL_HAVE_WINDOW_DISPMANX
51 #include "../dispmanx/gstglwindow_dispmanx_egl.h"
52 #endif
53 #if GST_GL_HAVE_WINDOW_GBM
54 #include "../gbm/gstglwindow_gbm_egl.h"
55 #endif
56 #if GST_GL_HAVE_WINDOW_VIV_FB
57 #include "../viv-fb/gstglwindow_viv_fb_egl.h"
58 #endif
59 
60 #define GST_CAT_DEFAULT gst_gl_context_debug
61 
62 static gboolean gst_gl_context_egl_create_context (GstGLContext * context,
63     GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
64 static void gst_gl_context_egl_destroy_context (GstGLContext * context);
65 static gboolean gst_gl_context_egl_choose_format (GstGLContext * context,
66     GError ** error);
67 
68 static gboolean gst_gl_context_egl_activate (GstGLContext * context,
69     gboolean activate);
70 static void gst_gl_context_egl_swap_buffers (GstGLContext * context);
71 static guintptr gst_gl_context_egl_get_gl_context (GstGLContext * context);
72 static GstGLAPI gst_gl_context_egl_get_gl_api (GstGLContext * context);
73 static GstGLPlatform gst_gl_context_egl_get_gl_platform (GstGLContext *
74     context);
75 static gboolean gst_gl_context_egl_check_feature (GstGLContext * context,
76     const gchar * feature);
77 static void gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
78     gint * major, gint * minor);
79 static GstStructure *gst_gl_context_egl_get_config (GstGLContext * context);
80 static gboolean gst_gl_context_egl_request_config (GstGLContext * context,
81     GstStructure * config);
82 
83 G_DEFINE_TYPE (GstGLContextEGL, gst_gl_context_egl, GST_TYPE_GL_CONTEXT);
84 
85 static void
gst_gl_context_egl_class_init(GstGLContextEGLClass * klass)86 gst_gl_context_egl_class_init (GstGLContextEGLClass * klass)
87 {
88   GstGLContextClass *context_class = (GstGLContextClass *) klass;
89 
90   context_class->get_gl_context =
91       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_context);
92   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_egl_activate);
93   context_class->create_context =
94       GST_DEBUG_FUNCPTR (gst_gl_context_egl_create_context);
95   context_class->destroy_context =
96       GST_DEBUG_FUNCPTR (gst_gl_context_egl_destroy_context);
97   context_class->choose_format =
98       GST_DEBUG_FUNCPTR (gst_gl_context_egl_choose_format);
99   context_class->swap_buffers =
100       GST_DEBUG_FUNCPTR (gst_gl_context_egl_swap_buffers);
101 
102   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_api);
103   context_class->get_gl_platform =
104       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform);
105   context_class->get_proc_address =
106       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_proc_address);
107   context_class->check_feature =
108       GST_DEBUG_FUNCPTR (gst_gl_context_egl_check_feature);
109   context_class->get_current_context =
110       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_current_context);
111   context_class->get_gl_platform_version =
112       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform_version);
113   context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_config);
114   context_class->request_config =
115       GST_DEBUG_FUNCPTR (gst_gl_context_egl_request_config);
116 }
117 
118 static void
gst_gl_context_egl_init(GstGLContextEGL * context)119 gst_gl_context_egl_init (GstGLContextEGL * context)
120 {
121 }
122 
123 /* Must be called in the gl thread */
124 GstGLContextEGL *
gst_gl_context_egl_new(GstGLDisplay * display)125 gst_gl_context_egl_new (GstGLDisplay * display)
126 {
127   GstGLContextEGL *context;
128 
129   /* XXX: display type could theoretically be anything, as long as
130    * eglGetDisplay supports it. */
131   context = g_object_new (GST_TYPE_GL_CONTEXT_EGL, NULL);
132   gst_object_ref_sink (context);
133 
134   return context;
135 }
136 
137 static gboolean
gst_gl_context_egl_choose_format(GstGLContext * context,GError ** error)138 gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error)
139 {
140 #if GST_GL_HAVE_WINDOW_X11
141   if (GST_IS_GL_WINDOW_X11 (context->window)) {
142     GstGLWindow *window = gst_gl_context_get_window (context);
143     GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
144     gint ret;
145 
146     window_x11->visual_info = g_new0 (XVisualInfo, 1);
147     ret = XMatchVisualInfo (window_x11->device, window_x11->screen_num,
148         window_x11->depth, TrueColor, window_x11->visual_info);
149 
150     gst_object_unref (window);
151 
152     if (ret == 0) {
153       g_set_error (error, GST_GL_CONTEXT_ERROR,
154           GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to match XVisualInfo");
155       return FALSE;
156     }
157   }
158 #endif
159 
160   return TRUE;
161 }
162 
163 static GstGLAPI
egl_conformant_to_gst(int conformant)164 egl_conformant_to_gst (int conformant)
165 {
166   GstGLAPI ret = GST_GL_API_NONE;
167 
168   if (conformant & EGL_OPENGL_BIT)
169     ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
170   if (conformant & EGL_OPENGL_ES_BIT)
171     ret |= GST_GL_API_GLES1;
172   if (conformant & EGL_OPENGL_ES2_BIT)
173     ret |= GST_GL_API_GLES2;
174 #if defined(EGL_KHR_create_context)
175   if (conformant & EGL_OPENGL_ES3_BIT_KHR)
176     /* FIXME: need another gles3 value? */
177     ret |= GST_GL_API_GLES2;
178 #endif
179 #if 0
180   if (conformant & EGL_OPENVG_BIT)
181     conformant_values[i++] = "OpenVG";
182 #endif
183 
184   return ret;
185 }
186 
187 static GstGLConfigSurfaceType
egl_surface_type_to_gst(int surface)188 egl_surface_type_to_gst (int surface)
189 {
190   GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
191 
192   if (surface & EGL_WINDOW_BIT)
193     ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
194   if (surface & EGL_PBUFFER_BIT)
195     ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER;
196 #if 0
197   if (surface & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)
198     surface_values[i++] = "multisample-resolve-box";
199   if (surface & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
200     surface_values[i++] = "swap-behaviour-preserved";
201   if (surface & EGL_VG_ALPHA_FORMAT_PRE_BIT)
202     surface_values[i++] = "vg-alpha-format-pre";
203   if (surface & EGL_VG_COLORSPACE_LINEAR_BIT)
204     surface_values[i++] = "vg-colorspace-linear";
205 #endif
206   return ret;
207 }
208 
209 static GstGLConfigCaveat
egl_caveat_to_gst(int caveat)210 egl_caveat_to_gst (int caveat)
211 {
212   switch (caveat) {
213     case EGL_NONE:
214       return GST_GL_CONFIG_CAVEAT_NONE;
215     case EGL_SLOW_CONFIG:
216       return GST_GL_CONFIG_CAVEAT_SLOW;
217     case EGL_NON_CONFORMANT_CONFIG:
218       return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
219     default:
220       GST_WARNING ("unknown EGL caveat value %u (0x%x)", caveat, caveat);
221       return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
222   }
223 }
224 
225 static GstStructure *
egl_config_to_structure(EGLDisplay egl_display,EGLConfig config)226 egl_config_to_structure (EGLDisplay egl_display, EGLConfig config)
227 {
228   GstStructure *ret;
229   int val;
230   int buffer_type;
231 
232   if (!egl_display)
233     return NULL;
234 
235   ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
236       GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
237           GST_GL_PLATFORM_EGL), NULL);
238 
239   if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_ID, &val))
240     goto failure;
241   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int,
242           val), NULL);
243 
244 #if 0
245   {
246     /* Don't know how to translate this value, it's platform and implementation
247      * dependant
248      */
249     int native_visual_type;
250     if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_TYPE,
251             &native_visual_type))
252       goto failure;
253   }
254 #endif
255 
256   if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_ID, &val))
257     goto failure;
258   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
259           guint, val), NULL);
260 
261   if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_RENDERABLE, &val))
262     goto failure;
263   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE,
264           gboolean, val), NULL);
265 
266   if (!eglGetConfigAttrib (egl_display, config, EGL_CONFORMANT, &val))
267     goto failure;
268   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFORMANT_API,
269           GstGLAPI, egl_conformant_to_gst (val)), NULL);
270 
271   if (!eglGetConfigAttrib (egl_display, config, EGL_RENDERABLE_TYPE, &val))
272     goto failure;
273   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RENDERABLE_API,
274           GstGLAPI, egl_conformant_to_gst (val)), NULL);
275 
276   if (!eglGetConfigAttrib (egl_display, config, EGL_SURFACE_TYPE, &val))
277     goto failure;
278   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
279           GstGLConfigSurfaceType, egl_surface_type_to_gst (val)), NULL);
280 
281   if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_CAVEAT, &val))
282     goto failure;
283   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT,
284           GstGLConfigCaveat, egl_caveat_to_gst (val)), NULL);
285 
286   if (!eglGetConfigAttrib (egl_display, config, EGL_LEVEL, &val))
287     goto failure;
288   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val),
289       NULL);
290 
291 
292   if (!eglGetConfigAttrib (egl_display, config, EGL_COLOR_BUFFER_TYPE,
293           &buffer_type))
294     goto failure;
295 
296   if (buffer_type == EGL_RGB_BUFFER) {
297     if (!eglGetConfigAttrib (egl_display, config, EGL_RED_SIZE, &val))
298       goto failure;
299     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
300             val), NULL);
301 
302     if (!eglGetConfigAttrib (egl_display, config, EGL_GREEN_SIZE, &val))
303       goto failure;
304     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
305             val), NULL);
306 
307     if (!eglGetConfigAttrib (egl_display, config, EGL_BLUE_SIZE, &val))
308       goto failure;
309     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
310             val), NULL);
311 
312     if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val))
313       goto failure;
314     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
315             val), NULL);
316   } else if (buffer_type == EGL_LUMINANCE_BUFFER) {
317     if (!eglGetConfigAttrib (egl_display, config, EGL_LUMINANCE_SIZE, &val))
318       goto failure;
319     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LUMINANCE_SIZE,
320             int, val), NULL);
321 
322     if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val))
323       goto failure;
324     gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
325             val), NULL);
326   } else {
327     GST_WARNING ("unknown EGL_COLOR_BUFFER_TYPE value %x", buffer_type);
328     goto failure;
329   }
330 
331   if (!eglGetConfigAttrib (egl_display, config, EGL_DEPTH_SIZE, &val))
332     goto failure;
333   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
334           val), NULL);
335 
336   if (!eglGetConfigAttrib (egl_display, config, EGL_STENCIL_SIZE, &val))
337     goto failure;
338   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
339           val), NULL);
340 
341   if (!eglGetConfigAttrib (egl_display, config, EGL_MIN_SWAP_INTERVAL, &val))
342     goto failure;
343   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MIN_SWAP_INTERVAL,
344           int, val), NULL);
345 
346   if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_SWAP_INTERVAL, &val))
347     goto failure;
348   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_SWAP_INTERVAL,
349           int, val), NULL);
350 
351   if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_WIDTH, &val))
352     goto failure;
353   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH,
354           int, val), NULL);
355 
356   if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_HEIGHT, &val))
357     goto failure;
358   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT,
359           int, val), NULL);
360 
361   if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_PIXELS, &val))
362     goto failure;
363   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS,
364           int, val), NULL);
365 
366   if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLE_BUFFERS, &val))
367     goto failure;
368   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLE_BUFFERS, int,
369           val), NULL);
370 
371   if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLES, &val))
372     goto failure;
373   gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLES, int, val),
374       NULL);
375 
376   return ret;
377 
378 failure:
379   gst_structure_free (ret);
380   return NULL;
381 }
382 
383 static void
gst_gl_context_egl_dump_config(GstGLContextEGL * egl,EGLConfig config)384 gst_gl_context_egl_dump_config (GstGLContextEGL * egl, EGLConfig config)
385 {
386   int id;
387   int buffer_type;
388 
389   if (!egl->egl_display)
390     return;
391 
392   {
393     int native_visual_id, native_visual_type;
394     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFIG_ID, &id))
395       return;
396     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_NATIVE_VISUAL_ID,
397             &native_visual_id))
398       return;
399     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_NATIVE_VISUAL_TYPE,
400             &native_visual_type))
401       return;
402     GST_DEBUG_OBJECT (egl, "dumping EGLConfig %p with id 0x%x and "
403         "native visual id 0x%x of type 0x%x", config, id, native_visual_id,
404         native_visual_type);
405   }
406 
407   {
408 #define MAX_CONFORMANT 8
409     int conformant, i = 0;
410     const char *conformant_values[MAX_CONFORMANT] = { NULL, };
411     char *conformant_str = NULL;;
412 
413     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFORMANT,
414             &conformant))
415       return;
416 
417     if (conformant & EGL_OPENGL_BIT)
418       conformant_values[i++] = "OpenGL";
419     if (conformant & EGL_OPENGL_ES_BIT)
420       conformant_values[i++] = "OpenGL ES";
421     if (conformant & EGL_OPENGL_ES2_BIT)
422       conformant_values[i++] = "OpenGL ES 2.x";
423 #if defined(EGL_KHR_create_context)
424     if (conformant & EGL_OPENGL_ES3_BIT_KHR)
425       conformant_values[i++] = "OpenGL ES 3.x";
426 #endif
427     if (conformant & EGL_OPENVG_BIT)
428       conformant_values[i++] = "OpenVG";
429 
430     /* bad things have happened if this fails: we haven't allocated enough
431      * space to hold all the values */
432     g_assert (i < MAX_CONFORMANT);
433 
434     conformant_str = g_strjoinv ("|", (char **) conformant_values);
435     GST_DEBUG_OBJECT (egl, "Conformant for %s", conformant_str);
436     g_free (conformant_str);
437 #undef MAX_CONFORMANT
438   }
439 
440   {
441 #define MAX_RENDERABLE 8
442     int renderable, i = 0;
443     const char *renderable_values[MAX_RENDERABLE] = { NULL, };
444     char *renderable_str = NULL;
445 
446     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_RENDERABLE_TYPE,
447             &renderable))
448       return;
449 
450     if (renderable & EGL_OPENGL_BIT)
451       renderable_values[i++] = "OpenGL";
452     if (renderable & EGL_OPENGL_ES_BIT)
453       renderable_values[i++] = "OpenGL ES";
454     if (renderable & EGL_OPENGL_ES2_BIT)
455       renderable_values[i++] = "OpenGL ES 2.x";
456 #if defined(EGL_KHR_create_context)
457     if (renderable & EGL_OPENGL_ES3_BIT_KHR)
458       renderable_values[i++] = "OpenGL ES 3.x";
459 #endif
460     if (renderable & EGL_OPENVG_BIT)
461       renderable_values[i++] = "OpenVG";
462 
463     /* bad things have happened if this fails: we haven't allocated enough
464      * space to hold all the values */
465     g_assert (i < MAX_RENDERABLE);
466 
467     renderable_str = g_strjoinv ("|", (char **) renderable_values);
468     GST_DEBUG_OBJECT (egl, "Renderable for %s", renderable_str);
469     g_free (renderable_str);
470 #undef MAX_RENDERABLE
471   }
472 
473   {
474 #define MAX_SURFACE 8
475     int surface, i = 0;
476     const char *surface_values[MAX_SURFACE] = { NULL, };
477     char *surface_str = NULL;
478 
479     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SURFACE_TYPE,
480             &surface))
481       return;
482 
483     if (surface & EGL_WINDOW_BIT)
484       surface_values[i++] = "window";
485     if (surface & EGL_PBUFFER_BIT)
486       surface_values[i++] = "pbuffer";
487     if (surface & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)
488       surface_values[i++] = "multisample-resolve-box";
489     if (surface & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
490       surface_values[i++] = "swap-behaviour-preserved";
491     if (surface & EGL_VG_ALPHA_FORMAT_PRE_BIT)
492       surface_values[i++] = "vg-alpha-format-pre";
493     if (surface & EGL_VG_COLORSPACE_LINEAR_BIT)
494       surface_values[i++] = "vg-colorspace-linear";
495 
496     /* bad things have happened if this fails: we haven't allocated enough
497      * space to hold all the values */
498     g_assert (i < MAX_SURFACE);
499 
500     surface_str = g_strjoinv ("|", (char **) surface_values);
501     GST_DEBUG_OBJECT (egl, "Surface for (0x%x) %s", surface, surface_str);
502     g_free (surface_str);
503 #undef MAX_RENDERABLE
504   }
505 
506   {
507 #define MAX_CAVEAT 8
508     int caveat, i = 0;
509     const char *caveat_values[MAX_CAVEAT] = { NULL, };
510     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFIG_CAVEAT,
511             &caveat))
512       return;
513     if (caveat == EGL_SLOW_CONFIG) {
514       caveat_values[i++] = "slow";
515     } else if (caveat == EGL_NON_CONFORMANT_CONFIG) {
516       caveat_values[i++] = "non-conformant";
517     }
518     if (i > 0) {
519       char *caveat_str = g_strjoinv ("|", (char **) caveat_values);
520       GST_DEBUG_OBJECT (egl, "Advertised as %s", caveat_str);
521       g_free (caveat_str);
522     }
523 #undef MAX_CAVEAT
524   }
525 
526   if (!eglGetConfigAttrib (egl->egl_display, config, EGL_COLOR_BUFFER_TYPE,
527           &buffer_type))
528     return;
529   if (buffer_type == EGL_RGB_BUFFER) {
530     int red, blue, green, alpha;
531 
532     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_RED_SIZE, &red))
533       return;
534     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_GREEN_SIZE, &green))
535       return;
536     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_BLUE_SIZE, &blue))
537       return;
538     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_ALPHA_SIZE, &alpha))
539       return;
540 
541     GST_DEBUG_OBJECT (egl, "[R, G, B, A] = [%i, %i, %i, %i]", red, green, blue,
542         alpha);
543   } else if (buffer_type == EGL_LUMINANCE_BUFFER) {
544     int luminance, alpha;
545     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_LUMINANCE_SIZE,
546             &luminance))
547       return;
548     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_ALPHA_SIZE, &alpha))
549       return;
550     GST_DEBUG_OBJECT (egl, "[L, A] = [%i, %i]", luminance, alpha);
551   } else {
552     GST_WARNING_OBJECT (egl, "unknown EGL_COLOR_BUFFER_TYPE value %x",
553         buffer_type);
554     return;
555   }
556   {
557     int depth, stencil;
558     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_DEPTH_SIZE, &depth))
559       return;
560     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_STENCIL_SIZE,
561             &stencil))
562       return;
563     GST_DEBUG_OBJECT (egl, "[D, S] = [%i, %i]", depth, stencil);
564   }
565   {
566     int min, max;
567 
568     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MIN_SWAP_INTERVAL,
569             &min))
570       return;
571     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_SWAP_INTERVAL,
572             &max))
573       return;
574     GST_DEBUG_OBJECT (egl, "Swap interval range is [%i, %i]", min, max);
575   }
576   {
577     int width, height, pixels;
578 
579     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_WIDTH,
580             &width))
581       return;
582     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_HEIGHT,
583             &height))
584       return;
585     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_PIXELS,
586             &pixels))
587       return;
588     GST_DEBUG_OBJECT (egl,
589         "PBuffer maximum dimensions are [%i, %i]. Max pixels are %i", width,
590         height, pixels);
591   }
592   {
593     int sample_buffers, samples_per_pixel;
594 
595     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SAMPLE_BUFFERS,
596             &sample_buffers))
597       return;
598     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SAMPLES,
599             &samples_per_pixel))
600       return;
601     GST_DEBUG_OBJECT (egl, "Multisample buffers: %i and Samples per pixel: %i",
602         sample_buffers, samples_per_pixel);
603   }
604 }
605 
606 static void
gst_gl_context_egl_dump_all_configs(GstGLContextEGL * egl)607 gst_gl_context_egl_dump_all_configs (GstGLContextEGL * egl)
608 {
609   int i, n;
610   EGLConfig *configs;
611 
612   if (!eglGetConfigs (egl->egl_display, NULL, 0, &n)) {
613     GST_WARNING_OBJECT (egl, "Failed to get number of EGLConfig's");
614     return;
615   }
616 
617   configs = g_new0 (EGLConfig, n);
618   if (!eglGetConfigs (egl->egl_display, configs, n, &n)) {
619     GST_WARNING_OBJECT (egl, "Failed to get the list of EGLConfig's");
620     goto out;
621   }
622 
623   for (i = 0; i < n; i++)
624     gst_gl_context_egl_dump_config (egl, configs[i]);
625 
626 out:
627   g_free (configs);
628 }
629 
630 static gboolean
gst_gl_context_egl_choose_config(GstGLContextEGL * egl,GstGLAPI gl_api,gint major,GError ** error)631 gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api,
632     gint major, GError ** error)
633 {
634   gboolean create_context;
635   EGLint numConfigs;
636   gint i, n;
637   EGLint config_attrib[20];
638   EGLint egl_api = 0;
639   EGLBoolean ret = EGL_FALSE;
640   EGLint surface_type = EGL_WINDOW_BIT;
641   EGLint alpha_size = 1;
642   GstGLWindow *window;
643 
644   window = gst_gl_context_get_window (GST_GL_CONTEXT (egl));
645 
646   if (!window || !gst_gl_window_has_output_surface (window)) {
647     GST_INFO_OBJECT (egl,
648         "gl window has no output surface, use pixel buffer surfaces");
649     surface_type = EGL_PBUFFER_BIT;
650   }
651 
652   if (window)
653     gst_object_unref (window);
654 
655   create_context =
656       gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
657   /* silence unused warnings */
658   (void) create_context;
659 
660   if (gl_api & GST_GL_API_GLES2) {
661     if (major == 3) {
662 #if defined(EGL_KHR_create_context)
663       if (create_context) {
664         egl_api = EGL_OPENGL_ES3_BIT_KHR;
665       } else
666 #endif
667       {
668         return FALSE;
669       }
670     } else {
671       egl_api = EGL_OPENGL_ES2_BIT;
672     }
673   } else
674     egl_api = EGL_OPENGL_BIT;
675 
676 try_again:
677   i = 0;
678   n = G_N_ELEMENTS (config_attrib);
679   config_attrib[i++] = EGL_SURFACE_TYPE;
680   config_attrib[i++] = surface_type;
681   config_attrib[i++] = EGL_RENDERABLE_TYPE;
682   config_attrib[i++] = egl_api;
683 
684   if (egl->requested_config) {
685 #define TRANSFORM_VALUE(GL_CONF_NAME,EGL_ATTR_NAME) \
686   G_STMT_START { \
687     if (gst_structure_has_field_typed (egl->requested_config, \
688           GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
689           GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \
690       int val; \
691       if (gst_structure_get (egl->requested_config, \
692           GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
693           GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \
694         config_attrib[i++] = EGL_ATTR_NAME; \
695         config_attrib[i++] = (int) val; \
696         g_assert (i <= n); \
697       } \
698     } \
699   } G_STMT_END
700 
701     TRANSFORM_VALUE (CONFIG_ID, EGL_CONFIG_ID);
702     TRANSFORM_VALUE (RED_SIZE, EGL_RED_SIZE);
703     TRANSFORM_VALUE (GREEN_SIZE, EGL_GREEN_SIZE);
704     TRANSFORM_VALUE (BLUE_SIZE, EGL_BLUE_SIZE);
705     TRANSFORM_VALUE (ALPHA_SIZE, EGL_ALPHA_SIZE);
706     TRANSFORM_VALUE (DEPTH_SIZE, EGL_DEPTH_SIZE);
707     TRANSFORM_VALUE (STENCIL_SIZE, EGL_STENCIL_SIZE);
708     /* TODO: more values */
709 #undef TRANSFORM_VALUE
710   } else {
711     config_attrib[i++] = EGL_DEPTH_SIZE;
712     config_attrib[i++] = 16;
713     config_attrib[i++] = EGL_RED_SIZE;
714     config_attrib[i++] = 1;
715     config_attrib[i++] = EGL_GREEN_SIZE;
716     config_attrib[i++] = 1;
717     config_attrib[i++] = EGL_BLUE_SIZE;
718     config_attrib[i++] = 1;
719     config_attrib[i++] = EGL_ALPHA_SIZE;
720     config_attrib[i++] = alpha_size;
721   }
722 
723   config_attrib[i++] = EGL_NONE;
724   g_assert (i <= n);
725 
726   ret = eglChooseConfig (egl->egl_display, config_attrib,
727       &egl->egl_config, 1, &numConfigs);
728 
729   if (ret && numConfigs == 0) {
730     if (surface_type == EGL_PBUFFER_BIT) {
731       surface_type = EGL_WINDOW_BIT;
732       GST_TRACE_OBJECT (egl, "Retrying config with window bit");
733       goto try_again;
734     }
735 
736     if (alpha_size == 1) {
737       alpha_size = 0;
738       GST_TRACE_OBJECT (egl, "Retrying config not forcing an alpha channel");
739       goto try_again;
740     }
741   }
742 
743   if (ret && numConfigs == 1) {
744     GST_INFO ("config set: %" G_GUINTPTR_FORMAT ", %u",
745         (guintptr) egl->egl_config, (unsigned int) numConfigs);
746   } else {
747     if (!ret) {
748       g_set_error (error, GST_GL_CONTEXT_ERROR,
749           GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to choose EGLConfig: %s",
750           gst_egl_get_error_string (eglGetError ()));
751     } else if (numConfigs <= 1) {
752       g_set_error_literal (error, GST_GL_CONTEXT_ERROR,
753           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
754           "Could not find a compatible EGLConfig:");
755     } else {
756       g_warn_if_reached ();
757     }
758     goto failure;
759   }
760 
761   GST_DEBUG_OBJECT (egl, "chosen EGLConfig:");
762   gst_gl_context_egl_dump_config (egl, egl->egl_config);
763 
764   return TRUE;
765 
766 failure:
767   return FALSE;
768 }
769 
770 static EGLContext
_create_context_with_flags(GstGLContextEGL * egl,EGLContext share_context,GstGLAPI gl_api,gint major,gint minor,gint contextFlags,gint profileMask)771 _create_context_with_flags (GstGLContextEGL * egl, EGLContext share_context,
772     GstGLAPI gl_api, gint major, gint minor, gint contextFlags,
773     gint profileMask)
774 {
775   gboolean create_context;
776 #define N_ATTRIBS 20
777   gint attribs[N_ATTRIBS];
778   gint n = 0;
779 
780   /* fail creation of apis/versions/flags that require EGL_KHR_create_context
781    * if the extension doesn't exist, namely:0
782    *
783    * - profile mask
784    * - context flags
785    * - GL3 > 3.1
786    * - GLES2 && minor > 0
787    */
788   create_context =
789       gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
790   (void) create_context;
791   if (!create_context && (profileMask || contextFlags
792           || ((gl_api & GST_GL_API_OPENGL3)
793               && GST_GL_CHECK_GL_VERSION (major, minor, 3, 2))
794           || ((gl_api & GST_GL_API_GLES2) && minor > 0))) {
795     return 0;
796   }
797 
798   GST_DEBUG_OBJECT (egl, "attempting to create OpenGL%s context version %d.%d "
799       "flags %x profile %x", gl_api & GST_GL_API_GLES2 ? " ES" : "", major,
800       minor, contextFlags, profileMask);
801 
802 #if defined(EGL_KHR_create_context)
803   if (create_context) {
804     if (major) {
805       attribs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
806       attribs[n++] = major;
807     }
808     if (minor) {
809       attribs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR;
810       attribs[n++] = minor;
811     }
812     if (contextFlags) {
813       attribs[n++] = EGL_CONTEXT_FLAGS_KHR;
814       attribs[n++] = contextFlags;
815     }
816     if (profileMask) {
817       attribs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
818       attribs[n++] = profileMask;
819     }
820   } else
821 #endif
822   {
823     attribs[n++] = EGL_CONTEXT_CLIENT_VERSION;
824     attribs[n++] = major;
825   }
826   attribs[n++] = EGL_NONE;
827 
828   g_assert (n < N_ATTRIBS);
829 #undef N_ATTRIBS
830 
831   return eglCreateContext (egl->egl_display, egl->egl_config, share_context,
832       attribs);
833 }
834 
835 static void
gst_gl_context_egl_window_handle_changed_cb(GstGLContextEGL * egl,GstGLWindow * window)836 gst_gl_context_egl_window_handle_changed_cb (GstGLContextEGL * egl,
837     GstGLWindow * window)
838 {
839   if (egl->egl_surface != EGL_NO_SURFACE) {
840     if (!eglDestroySurface (egl->egl_display, egl->egl_surface))
841       GST_WARNING_OBJECT (egl, "Failed to destroy old window surface: %s",
842           gst_egl_get_error_string (eglGetError ()));
843     egl->egl_surface = EGL_NO_SURFACE;
844   }
845 }
846 
847 static gboolean
gst_gl_context_egl_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)848 gst_gl_context_egl_create_context (GstGLContext * context,
849     GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
850 {
851   GstGLContextEGL *egl;
852   GstGLWindow *window = NULL;
853   guintptr window_handle = 0;
854   EGLint egl_major;
855   EGLint egl_minor;
856   gboolean need_surface = TRUE;
857   guintptr external_gl_context = 0;
858   guintptr egl_display;
859 
860   egl = GST_GL_CONTEXT_EGL (context);
861   window = gst_gl_context_get_window (context);
862 
863   GST_DEBUG_OBJECT (context, "Creating EGL context");
864 
865   if (other_context) {
866     if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) {
867       g_set_error (error, GST_GL_CONTEXT_ERROR,
868           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
869           "Cannot share context with non-EGL context");
870       goto failure;
871     }
872     external_gl_context = gst_gl_context_get_gl_context (other_context);
873   }
874 
875   if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)) ==
876       GST_GL_API_NONE) {
877     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
878         "EGL supports opengl or gles2");
879     goto failure;
880   }
881 
882   if (!egl->display_egl) {
883     GstGLDisplay *display = gst_gl_context_get_display (context);
884 
885     egl->display_egl = gst_gl_display_egl_from_gl_display (display);
886     if (!egl->display_egl) {
887       g_set_error (error, GST_GL_CONTEXT_ERROR,
888           GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
889           "Failed to create EGLDisplay from native display");
890       gst_object_unref (display);
891       goto failure;
892     }
893 
894     gst_object_unref (display);
895   }
896 
897   egl_display = gst_gl_display_get_handle (GST_GL_DISPLAY (egl->display_egl));
898   egl->egl_display = (EGLDisplay) egl_display;
899 
900   if (eglInitialize (egl->egl_display, &egl_major, &egl_minor)) {
901     GST_INFO ("egl initialized, version: %d.%d", egl_major, egl_minor);
902   } else {
903     g_set_error (error, GST_GL_CONTEXT_ERROR,
904         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
905         "Failed to initialize egl: %s",
906         gst_egl_get_error_string (eglGetError ()));
907     goto failure;
908   }
909 
910   egl->egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS);
911   GST_DEBUG_OBJECT (egl, "Have EGL extensions: %s", egl->egl_exts);
912 
913   gst_gl_context_egl_dump_all_configs (egl);
914 
915   if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) {
916     GstGLAPI chosen_gl_api = 0;
917     gint i;
918 
919     /* egl + opengl only available with EGL 1.4+ */
920     if (egl_major == 1 && egl_minor <= 3) {
921       if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) {
922         g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS,
923             "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)",
924             egl_major, egl_minor);
925         goto failure;
926       } else {
927         GST_WARNING
928             ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)",
929             egl_major, egl_minor);
930         if (gl_api & GST_GL_API_GLES2) {
931           goto try_gles2;
932         } else {
933           g_set_error (error, GST_GL_CONTEXT_ERROR,
934               GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
935               "Failed to choose a suitable OpenGL API");
936           goto failure;
937         }
938       }
939     }
940 
941     if (!eglBindAPI (EGL_OPENGL_API)) {
942       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
943           "Failed to bind OpenGL API: %s",
944           gst_egl_get_error_string (eglGetError ()));
945       goto failure;
946     }
947 
948     GST_INFO ("Bound OpenGL");
949 
950     /* api, version only matters for gles */
951     if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_OPENGL, 0, error)) {
952       g_assert (error == NULL || *error != NULL);
953       goto failure;
954     }
955 
956     for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
957       gint profileMask = 0;
958       gint contextFlags = 0;
959 
960       if (GST_GL_CHECK_GL_VERSION (opengl_versions[i].major,
961               opengl_versions[i].minor, 3, 2)) {
962         /* skip gl3 contexts if requested */
963         if ((gl_api & GST_GL_API_OPENGL3) == 0)
964           continue;
965 
966         chosen_gl_api = GST_GL_API_OPENGL3;
967 #if defined(EGL_KHR_create_context)
968         profileMask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
969         contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
970 #endif
971       } else if (opengl_versions[i].major == 3 && opengl_versions[i].minor == 1) {
972         /* skip 3.1, the implementation is free to give us either a core or a
973          * compatibility context (we have no say) */
974         continue;
975       } else {
976         /* skip legacy contexts if requested */
977         if ((gl_api & GST_GL_API_OPENGL) == 0)
978           continue;
979 
980         chosen_gl_api = GST_GL_API_OPENGL;
981       }
982 
983       egl->egl_context =
984           _create_context_with_flags (egl, (EGLContext) external_gl_context,
985           chosen_gl_api, opengl_versions[i].major,
986           opengl_versions[i].minor, contextFlags, profileMask);
987 
988       if (egl->egl_context)
989         break;
990 
991 #if defined(EGL_KHR_create_context)
992       profileMask &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
993 
994       egl->egl_context =
995           _create_context_with_flags (egl, (EGLContext) external_gl_context,
996           chosen_gl_api, opengl_versions[i].major,
997           opengl_versions[i].minor, contextFlags, profileMask);
998 
999       if (egl->egl_context)
1000         break;
1001 #endif
1002     }
1003 
1004     egl->gl_api = chosen_gl_api;
1005   } else if (gl_api & GST_GL_API_GLES2) {
1006     gint i;
1007 
1008   try_gles2:
1009     if (!eglBindAPI (EGL_OPENGL_ES_API)) {
1010       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1011           "Failed to bind OpenGL|ES API: %s",
1012           gst_egl_get_error_string (eglGetError ()));
1013       goto failure;
1014     }
1015 
1016     GST_INFO ("Bound OpenGL|ES");
1017 
1018     for (i = 0; i < G_N_ELEMENTS (gles2_versions); i++) {
1019       gint profileMask = 0;
1020       gint contextFlags = 0;
1021       guint maj = gles2_versions[i].major;
1022       guint min = gles2_versions[i].minor;
1023 
1024       if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_GLES2, maj, error)) {
1025         GST_DEBUG_OBJECT (context, "Failed to choose a GLES%d config: %s",
1026             maj, error && *error ? (*error)->message : "Unknown");
1027         g_clear_error (error);
1028         continue;
1029       }
1030 #if defined(EGL_KHR_create_context)
1031       /* try a debug context */
1032       contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
1033 
1034       egl->egl_context =
1035           _create_context_with_flags (egl, (EGLContext) external_gl_context,
1036           GST_GL_API_GLES2, maj, min, contextFlags, profileMask);
1037 
1038       if (egl->egl_context)
1039         break;
1040 
1041       /* try without a debug context */
1042       contextFlags &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
1043 #endif
1044 
1045       egl->egl_context =
1046           _create_context_with_flags (egl, (EGLContext) external_gl_context,
1047           GST_GL_API_GLES2, maj, min, contextFlags, profileMask);
1048 
1049       if (egl->egl_context)
1050         break;
1051     }
1052     egl->gl_api = GST_GL_API_GLES2;
1053   }
1054 
1055   if (egl->egl_context != EGL_NO_CONTEXT) {
1056     GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT,
1057         (guintptr) egl->egl_context);
1058   } else {
1059     g_set_error (error, GST_GL_CONTEXT_ERROR,
1060         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
1061         "Failed to create a OpenGL context: %s",
1062         gst_egl_get_error_string (eglGetError ()));
1063     goto failure;
1064   }
1065   /* FIXME do we want a window vfunc ? */
1066 #if GST_GL_HAVE_WINDOW_X11
1067   if (GST_IS_GL_WINDOW_X11 (context->window)) {
1068     gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window);
1069   }
1070 #endif
1071 
1072   if (other_context == NULL) {
1073     /* FIXME: fails to show two outputs at all.  We need a property/option for
1074      * glimagesink to say its a visible context */
1075 #if GST_GL_HAVE_WINDOW_WAYLAND
1076     if (GST_IS_GL_WINDOW_WAYLAND_EGL (context->window)) {
1077       gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *)
1078           context->window);
1079     }
1080 #endif
1081 #if GST_GL_HAVE_WINDOW_WIN32
1082     if (GST_IS_GL_WINDOW_WIN32 (context->window)) {
1083       gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window,
1084           NULL);
1085     }
1086 #endif
1087 #if GST_GL_HAVE_WINDOW_DISPMANX
1088     if (GST_IS_GL_WINDOW_DISPMANX_EGL (context->window)) {
1089       gst_gl_window_dispmanx_egl_create_window ((GstGLWindowDispmanxEGL *)
1090           context->window);
1091     }
1092 #endif
1093 #if GST_GL_HAVE_WINDOW_GBM
1094     if (GST_IS_GL_WINDOW_GBM_EGL (context->window)) {
1095       gst_gl_window_gbm_egl_create_window ((GstGLWindowGBMEGL *)
1096           context->window);
1097     }
1098 #endif
1099 #if GST_GL_HAVE_WINDOW_VIV_FB
1100     if (GST_IS_GL_WINDOW_VIV_FB_EGL (context->window)) {
1101       gst_gl_window_viv_fb_egl_create_window ((GstGLWindowVivFBEGL *)
1102           context->window);
1103     }
1104 #endif
1105   }
1106 
1107   if (window)
1108     window_handle = gst_gl_window_get_window_handle (window);
1109 
1110   if (window_handle) {
1111 #if GST_GL_HAVE_WINDOW_WINRT && defined (EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER)
1112     const EGLint attrs[] = {
1113       /* EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is an optimization that can
1114        * have large performance benefits on mobile devices. */
1115       EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
1116       EGL_NONE
1117     };
1118 #else
1119     const EGLint *attrs = NULL;
1120 #endif
1121 
1122     GST_DEBUG ("Creating EGLSurface from window_handle %p",
1123         (void *) window_handle);
1124     egl->egl_surface =
1125         eglCreateWindowSurface (egl->egl_display, egl->egl_config,
1126         (EGLNativeWindowType) window_handle, attrs);
1127   } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context",
1128           egl->egl_exts)) {
1129     EGLint surface_attrib[7];
1130     gint j = 0;
1131 
1132     GST_DEBUG ("Surfaceless context, creating PBufferSurface");
1133     /* FIXME: Width/height doesn't seem to matter but we can't leave them
1134      * at 0, otherwise X11 complains about BadValue */
1135     surface_attrib[j++] = EGL_WIDTH;
1136     surface_attrib[j++] = 1;
1137     surface_attrib[j++] = EGL_HEIGHT;
1138     surface_attrib[j++] = 1;
1139     surface_attrib[j++] = EGL_LARGEST_PBUFFER;
1140     surface_attrib[j++] = EGL_TRUE;
1141     surface_attrib[j++] = EGL_NONE;
1142 
1143     egl->egl_surface =
1144         eglCreatePbufferSurface (egl->egl_display, egl->egl_config,
1145         surface_attrib);
1146   } else {
1147     GST_DEBUG ("No surface/handle !");
1148     egl->egl_surface = EGL_NO_SURFACE;
1149     need_surface = FALSE;
1150   }
1151 
1152   if (need_surface) {
1153     if (egl->egl_surface != EGL_NO_SURFACE) {
1154       GST_INFO ("surface created");
1155     } else {
1156       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
1157           "Failed to create window surface: %s",
1158           gst_egl_get_error_string (eglGetError ()));
1159       goto failure;
1160     }
1161   }
1162   egl->egl_major = egl_major;
1163   egl->egl_minor = egl_minor;
1164 
1165   if (window) {
1166     egl->window_handle_signal = g_signal_connect_swapped (window,
1167         "window-handle-changed",
1168         G_CALLBACK (gst_gl_context_egl_window_handle_changed_cb), egl);
1169     gst_object_unref (window);
1170   }
1171 
1172   return TRUE;
1173 
1174 failure:
1175   if (window)
1176     gst_object_unref (window);
1177 
1178   return FALSE;
1179 }
1180 
1181 static void
gst_gl_context_egl_destroy_context(GstGLContext * context)1182 gst_gl_context_egl_destroy_context (GstGLContext * context)
1183 {
1184   GstGLContextEGL *egl;
1185   GstGLWindow *window;
1186 
1187   egl = GST_GL_CONTEXT_EGL (context);
1188   window = gst_gl_context_get_window (context);
1189 
1190   if (window && egl->window_handle_signal) {
1191     g_signal_handler_disconnect (window, egl->window_handle_signal);
1192     egl->window_handle_signal = 0;
1193   }
1194   if (window) {
1195     gst_object_unref (window);
1196   }
1197 
1198   gst_gl_context_egl_activate (context, FALSE);
1199 
1200   if (egl->egl_surface) {
1201     eglDestroySurface (egl->egl_display, egl->egl_surface);
1202     egl->egl_surface = EGL_NO_SURFACE;
1203   }
1204 
1205   if (egl->egl_context) {
1206     eglDestroyContext (egl->egl_display, egl->egl_context);
1207     egl->egl_context = NULL;
1208   }
1209 
1210   eglReleaseThread ();
1211 
1212   if (egl->display_egl) {
1213     gst_object_unref (egl->display_egl);
1214     egl->display_egl = NULL;
1215   }
1216 
1217   if (egl->requested_config)
1218     gst_structure_free (egl->requested_config);
1219   egl->requested_config = NULL;
1220 }
1221 
1222 static gboolean
gst_gl_context_egl_activate(GstGLContext * context,gboolean activate)1223 gst_gl_context_egl_activate (GstGLContext * context, gboolean activate)
1224 {
1225   GstGLContextEGL *egl;
1226   gboolean result;
1227 
1228   egl = GST_GL_CONTEXT_EGL (context);
1229 
1230   if (activate) {
1231     GstGLWindow *window = gst_gl_context_get_window (context);
1232     guintptr handle = 0;
1233     /* Check if the backing handle changed */
1234     if (window) {
1235       handle = gst_gl_window_get_window_handle (window);
1236       gst_object_unref (window);
1237     }
1238     if (handle && (egl->egl_surface == EGL_NO_SURFACE)) {
1239 #if GST_GL_HAVE_WINDOW_WINRT && defined (EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER)
1240       const EGLint attrs[] = {
1241         /* EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is an optimization that can
1242          * have large performance benefits on mobile devices. */
1243         EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
1244         EGL_NONE
1245       };
1246 #else
1247       const EGLint *attrs = NULL;
1248 #endif
1249       GST_DEBUG_OBJECT (context,
1250           "Handle changed (have:%p, now:%p), switching surface",
1251           (void *) egl->window_handle, (void *) handle);
1252       egl->egl_surface =
1253           eglCreateWindowSurface (egl->egl_display, egl->egl_config,
1254           (EGLNativeWindowType) handle, attrs);
1255       egl->window_handle = handle;
1256 
1257       if (egl->egl_surface == EGL_NO_SURFACE) {
1258         GST_ERROR_OBJECT (context, "Failed to create window surface: %s",
1259             gst_egl_get_error_string (eglGetError ()));
1260         result = FALSE;
1261         goto done;
1262       }
1263     }
1264     result = eglMakeCurrent (egl->egl_display, egl->egl_surface,
1265         egl->egl_surface, egl->egl_context);
1266   } else {
1267     result = eglMakeCurrent (egl->egl_display, EGL_NO_SURFACE,
1268         EGL_NO_SURFACE, EGL_NO_CONTEXT);
1269   }
1270 
1271   if (!result) {
1272     GST_ERROR_OBJECT (context,
1273         "Failed to bind context to the current rendering thread: %s",
1274         gst_egl_get_error_string (eglGetError ()));
1275   }
1276 
1277 done:
1278   return result;
1279 }
1280 
1281 static guintptr
gst_gl_context_egl_get_gl_context(GstGLContext * context)1282 gst_gl_context_egl_get_gl_context (GstGLContext * context)
1283 {
1284   return (guintptr) GST_GL_CONTEXT_EGL (context)->egl_context;
1285 }
1286 
1287 static void
gst_gl_context_egl_swap_buffers(GstGLContext * context)1288 gst_gl_context_egl_swap_buffers (GstGLContext * context)
1289 {
1290   GstGLContextEGL *egl;
1291 
1292   egl = GST_GL_CONTEXT_EGL (context);
1293 
1294   eglSwapBuffers (egl->egl_display, egl->egl_surface);
1295 }
1296 
1297 static GstGLAPI
gst_gl_context_egl_get_gl_api(GstGLContext * context)1298 gst_gl_context_egl_get_gl_api (GstGLContext * context)
1299 {
1300   return GST_GL_CONTEXT_EGL (context)->gl_api;
1301 }
1302 
1303 static GstGLPlatform
gst_gl_context_egl_get_gl_platform(GstGLContext * context)1304 gst_gl_context_egl_get_gl_platform (GstGLContext * context)
1305 {
1306   return GST_GL_PLATFORM_EGL;
1307 }
1308 
1309 static GModule *module_egl;
1310 
1311 static gpointer
load_egl_module(gpointer user_data)1312 load_egl_module (gpointer user_data)
1313 {
1314 #ifdef GST_GL_LIBEGL_MODULE_NAME
1315   module_egl = g_module_open (GST_GL_LIBEGL_MODULE_NAME, G_MODULE_BIND_LAZY);
1316 #else
1317   /* On Linux the .so is only in -dev packages, try with a real soname
1318    * Proper compilers will optimize away the strcmp */
1319   if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
1320     module_egl = g_module_open ("libEGL.so.1", G_MODULE_BIND_LAZY);
1321 
1322   /* This automatically handles the suffix and even .la files */
1323   if (!module_egl)
1324     module_egl = g_module_open ("libEGL", G_MODULE_BIND_LAZY);
1325 #endif
1326 
1327   return NULL;
1328 }
1329 
1330 gpointer
gst_gl_context_egl_get_proc_address(GstGLAPI gl_api,const gchar * name)1331 gst_gl_context_egl_get_proc_address (GstGLAPI gl_api, const gchar * name)
1332 {
1333   gpointer result = NULL;
1334   static GOnce g_once = G_ONCE_INIT;
1335 
1336 #ifdef __APPLE__
1337 #if GST_GL_HAVE_OPENGL && !defined(GST_GL_LIBGL_MODULE_NAME)
1338   if (!result && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
1339     static GModule *module_opengl = NULL;
1340     if (g_once_init_enter (&module_opengl)) {
1341       GModule *setup_module_opengl =
1342           g_module_open ("libGL.dylib", G_MODULE_BIND_LAZY);
1343       g_once_init_leave (&module_opengl, setup_module_opengl);
1344     }
1345     if (module_opengl)
1346       g_module_symbol (module_opengl, name, &result);
1347   }
1348 #endif
1349 #if GST_GL_HAVE_GLES2 && !defined(GST_GL_LIBGLESV2_MODULE_NAME)
1350   if (!result && (gl_api & (GST_GL_API_GLES2))) {
1351     static GModule *module_gles2 = NULL;
1352     if (g_once_init_enter (&module_gles2)) {
1353       GModule *setup_module_gles2 =
1354           g_module_open ("libGLESv2.dylib", G_MODULE_BIND_LAZY);
1355       g_once_init_leave (&module_gles2, setup_module_gles2);
1356     }
1357     if (module_gles2)
1358       g_module_symbol (module_gles2, name, &result);
1359   }
1360 #endif
1361 #endif // __APPLE__
1362 
1363   if (!result)
1364     result = gst_gl_context_default_get_proc_address (gl_api, name);
1365 
1366   g_once (&g_once, load_egl_module, NULL);
1367 
1368   if (!result && module_egl) {
1369     g_module_symbol (module_egl, name, &result);
1370   }
1371 
1372   /* FIXME: On Android this returns wrong addresses for non-EGL functions */
1373 #if GST_GL_HAVE_WINDOW_ANDROID
1374   if (!result && g_str_has_prefix (name, "egl")) {
1375 #else
1376   if (!result) {
1377     result = eglGetProcAddress (name);
1378 #endif
1379   }
1380 
1381   return result;
1382 }
1383 
1384 static gboolean
1385 gst_gl_context_egl_check_feature (GstGLContext * context, const gchar * feature)
1386 {
1387   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1388 
1389   return gst_gl_check_extension (feature, context_egl->egl_exts);
1390 }
1391 
1392 guintptr
1393 gst_gl_context_egl_get_current_context (void)
1394 {
1395   return (guintptr) eglGetCurrentContext ();
1396 }
1397 
1398 static void
1399 gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
1400     gint * major, gint * minor)
1401 {
1402   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1403 
1404   *major = context_egl->egl_major;
1405   *minor = context_egl->egl_minor;
1406 }
1407 
1408 static GstStructure *
1409 gst_gl_context_egl_get_config (GstGLContext * context)
1410 {
1411   GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
1412 
1413   g_return_val_if_fail (egl->egl_config, NULL);
1414 
1415   return egl_config_to_structure (egl->egl_display, egl->egl_config);
1416 }
1417 
1418 static gboolean
1419 gst_gl_context_egl_request_config (GstGLContext * context,
1420     GstStructure * config)
1421 {
1422   GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
1423 
1424   if (egl->requested_config)
1425     gst_structure_free (egl->requested_config);
1426   egl->requested_config = config;
1427 
1428   return TRUE;
1429 }
1430 
1431 gboolean
1432 gst_gl_context_egl_fill_info (GstGLContext * context, GError ** error)
1433 {
1434   EGLContext egl_context = (EGLContext) gst_gl_context_get_gl_context (context);
1435   GstGLDisplay *display_egl;
1436   GstStructure *config;
1437   EGLDisplay *egl_display;
1438   EGLConfig egl_config;
1439   int config_id, n_configs;
1440   int attrs[3];
1441 
1442   if (!egl_context) {
1443     g_set_error (error, GST_GL_CONTEXT_ERROR,
1444         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "no EGL context");
1445     return FALSE;
1446   }
1447 
1448   display_egl =
1449       GST_GL_DISPLAY (gst_gl_display_egl_from_gl_display (context->display));
1450   egl_display = (EGLDisplay) gst_gl_display_get_handle (display_egl);
1451 
1452   if (EGL_TRUE != eglQueryContext (egl_display, egl_context, EGL_CONFIG_ID,
1453           &config_id)) {
1454     GST_WARNING_OBJECT (context,
1455         "could not retrieve egl config id from egl context: %s",
1456         gst_egl_get_error_string (eglGetError ()));
1457     g_set_error (error, GST_GL_CONTEXT_ERROR,
1458         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1459         "could not retrieve egl config id from egl context: %s",
1460         gst_egl_get_error_string (eglGetError ()));
1461     goto failure;
1462   }
1463 
1464   if (config_id == 0) {
1465     GST_INFO_OBJECT (context, "egl config not available. ID is 0");
1466     gst_object_unref (display_egl);
1467     return TRUE;
1468   }
1469 
1470   attrs[0] = EGL_CONFIG_ID;
1471   attrs[1] = config_id;
1472   attrs[2] = EGL_NONE;
1473 
1474   if (EGL_TRUE != eglChooseConfig (egl_display, attrs, &egl_config, 1,
1475           &n_configs) || n_configs <= 0) {
1476     GST_WARNING_OBJECT (context,
1477         "could not retrieve egl config from its ID 0x%x. "
1478         "Wrong EGLDisplay or context?", config_id);
1479     g_set_error (error, GST_GL_CONTEXT_ERROR,
1480         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1481         "could not retrieve egl config from its ID 0x%x. "
1482         "Wrong EGLDisplay or context?", config_id);
1483     goto failure;
1484   }
1485 
1486   config = egl_config_to_structure (egl_display, egl_config);
1487   if (!config) {
1488     GST_WARNING_OBJECT (context, "could not transform config id 0x%x into "
1489         "GstStructure", config_id);
1490     g_set_error (error, GST_GL_CONTEXT_ERROR,
1491         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1492         "could not transform config id 0x%x into GstStructure", config_id);
1493     goto failure;
1494   }
1495 
1496   GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config);
1497 
1498   g_object_set_data_full (G_OBJECT (context),
1499       GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config,
1500       (GDestroyNotify) gst_structure_free);
1501 
1502   gst_object_unref (display_egl);
1503   return TRUE;
1504 
1505 failure:
1506   gst_object_unref (display_egl);
1507   return FALSE;
1508 }
1509