egl: handle configless contexts
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-base / gst-libs / gst / gl / egl / gstglcontext_egl.c
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
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
119 gst_gl_context_egl_init (GstGLContextEGL * context)
120 {
121 }
122
123 /* Must be called in the gl thread */
124 GstGLContextEGL *
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
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
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
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
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 *
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
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
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
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
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
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
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
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
1195   gst_gl_context_egl_activate (context, FALSE);
1196
1197   if (egl->egl_surface) {
1198     eglDestroySurface (egl->egl_display, egl->egl_surface);
1199     egl->egl_surface = EGL_NO_SURFACE;
1200   }
1201
1202   if (egl->egl_context) {
1203     eglDestroyContext (egl->egl_display, egl->egl_context);
1204     egl->egl_context = NULL;
1205   }
1206
1207   eglReleaseThread ();
1208
1209   if (egl->display_egl) {
1210     gst_object_unref (egl->display_egl);
1211     egl->display_egl = NULL;
1212   }
1213
1214   if (egl->requested_config)
1215     gst_structure_free (egl->requested_config);
1216   egl->requested_config = NULL;
1217 }
1218
1219 static gboolean
1220 gst_gl_context_egl_activate (GstGLContext * context, gboolean activate)
1221 {
1222   GstGLContextEGL *egl;
1223   gboolean result;
1224
1225   egl = GST_GL_CONTEXT_EGL (context);
1226
1227   if (activate) {
1228     GstGLWindow *window = gst_gl_context_get_window (context);
1229     guintptr handle = 0;
1230     /* Check if the backing handle changed */
1231     if (window) {
1232       handle = gst_gl_window_get_window_handle (window);
1233       gst_object_unref (window);
1234     }
1235     if (handle && (egl->egl_surface == EGL_NO_SURFACE)) {
1236 #if GST_GL_HAVE_WINDOW_WINRT && defined (EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER)
1237       const EGLint attrs[] = {
1238         /* EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER is an optimization that can
1239          * have large performance benefits on mobile devices. */
1240         EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
1241         EGL_NONE
1242       };
1243 #else
1244       const EGLint *attrs = NULL;
1245 #endif
1246       GST_DEBUG_OBJECT (context,
1247           "Handle changed (have:%p, now:%p), switching surface",
1248           (void *) egl->window_handle, (void *) handle);
1249       egl->egl_surface =
1250           eglCreateWindowSurface (egl->egl_display, egl->egl_config,
1251           (EGLNativeWindowType) handle, attrs);
1252       egl->window_handle = handle;
1253
1254       if (egl->egl_surface == EGL_NO_SURFACE) {
1255         GST_ERROR_OBJECT (context, "Failed to create window surface: %s",
1256             gst_egl_get_error_string (eglGetError ()));
1257         result = FALSE;
1258         goto done;
1259       }
1260     }
1261     result = eglMakeCurrent (egl->egl_display, egl->egl_surface,
1262         egl->egl_surface, egl->egl_context);
1263   } else {
1264     result = eglMakeCurrent (egl->egl_display, EGL_NO_SURFACE,
1265         EGL_NO_SURFACE, EGL_NO_CONTEXT);
1266   }
1267
1268   if (!result) {
1269     GST_ERROR_OBJECT (context,
1270         "Failed to bind context to the current rendering thread: %s",
1271         gst_egl_get_error_string (eglGetError ()));
1272   }
1273
1274 done:
1275   return result;
1276 }
1277
1278 static guintptr
1279 gst_gl_context_egl_get_gl_context (GstGLContext * context)
1280 {
1281   return (guintptr) GST_GL_CONTEXT_EGL (context)->egl_context;
1282 }
1283
1284 static void
1285 gst_gl_context_egl_swap_buffers (GstGLContext * context)
1286 {
1287   GstGLContextEGL *egl;
1288
1289   egl = GST_GL_CONTEXT_EGL (context);
1290
1291   eglSwapBuffers (egl->egl_display, egl->egl_surface);
1292 }
1293
1294 static GstGLAPI
1295 gst_gl_context_egl_get_gl_api (GstGLContext * context)
1296 {
1297   return GST_GL_CONTEXT_EGL (context)->gl_api;
1298 }
1299
1300 static GstGLPlatform
1301 gst_gl_context_egl_get_gl_platform (GstGLContext * context)
1302 {
1303   return GST_GL_PLATFORM_EGL;
1304 }
1305
1306 static GModule *module_egl;
1307
1308 static gpointer
1309 load_egl_module (gpointer user_data)
1310 {
1311 #ifdef GST_GL_LIBEGL_MODULE_NAME
1312   module_egl = g_module_open (GST_GL_LIBEGL_MODULE_NAME, G_MODULE_BIND_LAZY);
1313 #else
1314   /* On Linux the .so is only in -dev packages, try with a real soname
1315    * Proper compilers will optimize away the strcmp */
1316   if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
1317     module_egl = g_module_open ("libEGL.so.1", G_MODULE_BIND_LAZY);
1318
1319   /* This automatically handles the suffix and even .la files */
1320   if (!module_egl)
1321     module_egl = g_module_open ("libEGL", G_MODULE_BIND_LAZY);
1322 #endif
1323
1324   return NULL;
1325 }
1326
1327 gpointer
1328 gst_gl_context_egl_get_proc_address (GstGLAPI gl_api, const gchar * name)
1329 {
1330   gpointer result = NULL;
1331   static GOnce g_once = G_ONCE_INIT;
1332
1333 #ifdef __APPLE__
1334 #if GST_GL_HAVE_OPENGL && !defined(GST_GL_LIBGL_MODULE_NAME)
1335   if (!result && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
1336     static GModule *module_opengl = NULL;
1337     if (g_once_init_enter (&module_opengl)) {
1338       GModule *setup_module_opengl =
1339           g_module_open ("libGL.dylib", G_MODULE_BIND_LAZY);
1340       g_once_init_leave (&module_opengl, setup_module_opengl);
1341     }
1342     if (module_opengl)
1343       g_module_symbol (module_opengl, name, &result);
1344   }
1345 #endif
1346 #if GST_GL_HAVE_GLES2 && !defined(GST_GL_LIBGLESV2_MODULE_NAME)
1347   if (!result && (gl_api & (GST_GL_API_GLES2))) {
1348     static GModule *module_gles2 = NULL;
1349     if (g_once_init_enter (&module_gles2)) {
1350       GModule *setup_module_gles2 =
1351           g_module_open ("libGLESv2.dylib", G_MODULE_BIND_LAZY);
1352       g_once_init_leave (&module_gles2, setup_module_gles2);
1353     }
1354     if (module_gles2)
1355       g_module_symbol (module_gles2, name, &result);
1356   }
1357 #endif
1358 #endif // __APPLE__
1359
1360   if (!result)
1361     result = gst_gl_context_default_get_proc_address (gl_api, name);
1362
1363   g_once (&g_once, load_egl_module, NULL);
1364
1365   if (!result && module_egl) {
1366     g_module_symbol (module_egl, name, &result);
1367   }
1368
1369   /* FIXME: On Android this returns wrong addresses for non-EGL functions */
1370 #if GST_GL_HAVE_WINDOW_ANDROID
1371   if (!result && g_str_has_prefix (name, "egl")) {
1372 #else
1373   if (!result) {
1374     result = eglGetProcAddress (name);
1375 #endif
1376   }
1377
1378   return result;
1379 }
1380
1381 static gboolean
1382 gst_gl_context_egl_check_feature (GstGLContext * context, const gchar * feature)
1383 {
1384   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1385
1386   return gst_gl_check_extension (feature, context_egl->egl_exts);
1387 }
1388
1389 guintptr
1390 gst_gl_context_egl_get_current_context (void)
1391 {
1392   return (guintptr) eglGetCurrentContext ();
1393 }
1394
1395 static void
1396 gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
1397     gint * major, gint * minor)
1398 {
1399   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1400
1401   *major = context_egl->egl_major;
1402   *minor = context_egl->egl_minor;
1403 }
1404
1405 static GstStructure *
1406 gst_gl_context_egl_get_config (GstGLContext * context)
1407 {
1408   GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
1409
1410   g_return_val_if_fail (egl->egl_config, NULL);
1411
1412   return egl_config_to_structure (egl->egl_display, egl->egl_config);
1413 }
1414
1415 static gboolean
1416 gst_gl_context_egl_request_config (GstGLContext * context,
1417     GstStructure * config)
1418 {
1419   GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
1420
1421   if (egl->requested_config)
1422     gst_structure_free (egl->requested_config);
1423   egl->requested_config = config;
1424
1425   return TRUE;
1426 }
1427
1428 gboolean
1429 gst_gl_context_egl_fill_info (GstGLContext * context, GError ** error)
1430 {
1431   EGLContext egl_context = (EGLContext) gst_gl_context_get_gl_context (context);
1432   GstGLDisplay *display_egl;
1433   GstStructure *config;
1434   EGLDisplay *egl_display;
1435   EGLConfig egl_config;
1436   int config_id, n_configs;
1437   int attrs[3];
1438
1439   if (!egl_context) {
1440     g_set_error (error, GST_GL_CONTEXT_ERROR,
1441         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "no EGL context");
1442     return FALSE;
1443   }
1444
1445   display_egl =
1446       GST_GL_DISPLAY (gst_gl_display_egl_from_gl_display (context->display));
1447   egl_display = (EGLDisplay) gst_gl_display_get_handle (display_egl);
1448
1449   if (EGL_TRUE != eglQueryContext (egl_display, egl_context, EGL_CONFIG_ID,
1450           &config_id)) {
1451     GST_WARNING_OBJECT (context,
1452         "could not retrieve egl config id from egl context: %s",
1453         gst_egl_get_error_string (eglGetError ()));
1454     g_set_error (error, GST_GL_CONTEXT_ERROR,
1455         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1456         "could not retrieve egl config id from egl context: %s",
1457         gst_egl_get_error_string (eglGetError ()));
1458     goto failure;
1459   }
1460
1461   if (config_id == 0) {
1462     GST_INFO_OBJECT (context, "egl config not available. ID is 0");
1463     gst_object_unref (display_egl);
1464     return TRUE;
1465   }
1466
1467   attrs[0] = EGL_CONFIG_ID;
1468   attrs[1] = config_id;
1469   attrs[2] = EGL_NONE;
1470
1471   if (EGL_TRUE != eglChooseConfig (egl_display, attrs, &egl_config, 1,
1472           &n_configs) || n_configs <= 0) {
1473     GST_WARNING_OBJECT (context,
1474         "could not retrieve egl config from its ID 0x%x. "
1475         "Wrong EGLDisplay or context?", config_id);
1476     g_set_error (error, GST_GL_CONTEXT_ERROR,
1477         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1478         "could not retrieve egl config from its ID 0x%x. "
1479         "Wrong EGLDisplay or context?", config_id);
1480     goto failure;
1481   }
1482
1483   config = egl_config_to_structure (egl_display, egl_config);
1484   if (!config) {
1485     GST_WARNING_OBJECT (context, "could not transform config id 0x%x into "
1486         "GstStructure", config_id);
1487     g_set_error (error, GST_GL_CONTEXT_ERROR,
1488         GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1489         "could not transform config id 0x%x into GstStructure", config_id);
1490     goto failure;
1491   }
1492
1493   GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config);
1494
1495   g_object_set_data_full (G_OBJECT (context),
1496       GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config,
1497       (GDestroyNotify) gst_structure_free);
1498
1499   gst_object_unref (display_egl);
1500   return TRUE;
1501
1502 failure:
1503   gst_object_unref (display_egl);
1504   return FALSE;
1505 }