• 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/gstglcontext_private.h>
34 #include <gst/gl/gstglfeature.h>
35 #include <gst/gl/gstglwindow.h>
36 
37 #include "gstegl.h"
38 #include "../utils/opengl_versions.h"
39 #include "../utils/gles_versions.h"
40 
41 #if GST_GL_HAVE_WINDOW_X11
42 #include "../x11/gstglwindow_x11.h"
43 #include <gst/gl/x11/gstgldisplay_x11.h>
44 #endif
45 #if GST_GL_HAVE_WINDOW_WAYLAND
46 #include "../wayland/gstglwindow_wayland_egl.h"
47 #endif
48 #if GST_GL_HAVE_WINDOW_WIN32
49 #include "../win32/gstglwindow_win32.h"
50 #endif
51 #if GST_GL_HAVE_WINDOW_DISPMANX
52 #include "../dispmanx/gstglwindow_dispmanx_egl.h"
53 #endif
54 #if GST_GL_HAVE_WINDOW_GBM
55 #include "../gbm/gstglwindow_gbm_egl.h"
56 #endif
57 
58 #define GST_CAT_DEFAULT gst_gl_context_debug
59 
60 static gboolean gst_gl_context_egl_create_context (GstGLContext * context,
61     GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
62 static void gst_gl_context_egl_destroy_context (GstGLContext * context);
63 static gboolean gst_gl_context_egl_choose_format (GstGLContext * context,
64     GError ** error);
65 
66 static gboolean gst_gl_context_egl_activate (GstGLContext * context,
67     gboolean activate);
68 static void gst_gl_context_egl_swap_buffers (GstGLContext * context);
69 static guintptr gst_gl_context_egl_get_gl_context (GstGLContext * context);
70 static GstGLAPI gst_gl_context_egl_get_gl_api (GstGLContext * context);
71 static GstGLPlatform gst_gl_context_egl_get_gl_platform (GstGLContext *
72     context);
73 static gboolean gst_gl_context_egl_check_feature (GstGLContext * context,
74     const gchar * feature);
75 static void gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
76     gint * major, gint * minor);
77 
78 G_DEFINE_TYPE (GstGLContextEGL, gst_gl_context_egl, GST_TYPE_GL_CONTEXT);
79 
80 static void
gst_gl_context_egl_class_init(GstGLContextEGLClass * klass)81 gst_gl_context_egl_class_init (GstGLContextEGLClass * klass)
82 {
83   GstGLContextClass *context_class = (GstGLContextClass *) klass;
84 
85   context_class->get_gl_context =
86       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_context);
87   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_egl_activate);
88   context_class->create_context =
89       GST_DEBUG_FUNCPTR (gst_gl_context_egl_create_context);
90   context_class->destroy_context =
91       GST_DEBUG_FUNCPTR (gst_gl_context_egl_destroy_context);
92   context_class->choose_format =
93       GST_DEBUG_FUNCPTR (gst_gl_context_egl_choose_format);
94   context_class->swap_buffers =
95       GST_DEBUG_FUNCPTR (gst_gl_context_egl_swap_buffers);
96 
97   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_api);
98   context_class->get_gl_platform =
99       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform);
100   context_class->get_proc_address =
101       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_proc_address);
102   context_class->check_feature =
103       GST_DEBUG_FUNCPTR (gst_gl_context_egl_check_feature);
104   context_class->get_current_context =
105       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_current_context);
106   context_class->get_gl_platform_version =
107       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform_version);
108 }
109 
110 static void
gst_gl_context_egl_init(GstGLContextEGL * context)111 gst_gl_context_egl_init (GstGLContextEGL * context)
112 {
113 }
114 
115 /* Must be called in the gl thread */
116 GstGLContextEGL *
gst_gl_context_egl_new(GstGLDisplay * display)117 gst_gl_context_egl_new (GstGLDisplay * display)
118 {
119   GstGLContextEGL *context;
120 
121   /* XXX: display type could theoretically be anything, as long as
122    * eglGetDisplay supports it. */
123   context = g_object_new (GST_TYPE_GL_CONTEXT_EGL, NULL);
124   gst_object_ref_sink (context);
125 
126   return context;
127 }
128 
129 static gboolean
gst_gl_context_egl_choose_format(GstGLContext * context,GError ** error)130 gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error)
131 {
132 #if GST_GL_HAVE_WINDOW_X11
133   if (GST_IS_GL_WINDOW_X11 (context->window)) {
134     GstGLWindow *window = gst_gl_context_get_window (context);
135     GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
136     gint ret;
137 
138     window_x11->visual_info = g_new0 (XVisualInfo, 1);
139     ret = XMatchVisualInfo (window_x11->device, window_x11->screen_num,
140         window_x11->depth, TrueColor, window_x11->visual_info);
141 
142     gst_object_unref (window);
143 
144     if (ret == 0) {
145       g_set_error (error, GST_GL_CONTEXT_ERROR,
146           GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Failed to match XVisualInfo");
147       return FALSE;
148     }
149   }
150 #endif
151 
152   return TRUE;
153 }
154 
155 static void
gst_gl_context_egl_dump_config(GstGLContextEGL * egl,EGLConfig config)156 gst_gl_context_egl_dump_config (GstGLContextEGL * egl, EGLConfig config)
157 {
158   int id;
159   int buffer_type;
160 
161   if (!egl->egl_display)
162     return;
163 
164   {
165     int native_visual_id, native_visual_type;
166     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFIG_ID, &id))
167       return;
168     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_NATIVE_VISUAL_ID,
169             &native_visual_id))
170       return;
171     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_NATIVE_VISUAL_TYPE,
172             &native_visual_type))
173       return;
174     GST_DEBUG_OBJECT (egl, "dumping EGLConfig %p with id 0x%x and "
175         "native visual id 0x%x of type 0x%x", config, id, native_visual_id,
176         native_visual_type);
177   }
178 
179   {
180 #define MAX_CONFORMANT 8
181     int conformant, i = 0;
182     const char *conformant_values[MAX_CONFORMANT] = { NULL, };
183     char *conformant_str = NULL;;
184 
185     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFORMANT,
186             &conformant))
187       return;
188 
189     if (conformant & EGL_OPENGL_BIT)
190       conformant_values[i++] = "OpenGL";
191     if (conformant & EGL_OPENGL_ES_BIT)
192       conformant_values[i++] = "OpenGL ES";
193     if (conformant & EGL_OPENGL_ES2_BIT)
194       conformant_values[i++] = "OpenGL ES 2.x";
195 #if defined(EGL_KHR_create_context)
196     if (conformant & EGL_OPENGL_ES3_BIT_KHR)
197       conformant_values[i++] = "OpenGL ES 3.x";
198 #endif
199     if (conformant & EGL_OPENVG_BIT)
200       conformant_values[i++] = "OpenVG";
201 
202     /* bad things have happened if this fails: we haven't allocated enough
203      * space to hold all the values */
204     g_assert (i < MAX_CONFORMANT);
205 
206     conformant_str = g_strjoinv ("|", (char **) conformant_values);
207     GST_DEBUG_OBJECT (egl, "Conformant for %s", conformant_str);
208     g_free (conformant_str);
209 #undef MAX_CONFORMANT
210   }
211 
212   {
213 #define MAX_RENDERABLE 8
214     int renderable, i = 0;
215     const char *renderable_values[MAX_RENDERABLE] = { NULL, };
216     char *renderable_str = NULL;
217 
218     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_RENDERABLE_TYPE,
219             &renderable))
220       return;
221 
222     if (renderable & EGL_OPENGL_BIT)
223       renderable_values[i++] = "OpenGL";
224     if (renderable & EGL_OPENGL_ES_BIT)
225       renderable_values[i++] = "OpenGL ES";
226     if (renderable & EGL_OPENGL_ES2_BIT)
227       renderable_values[i++] = "OpenGL ES 2.x";
228 #if defined(EGL_KHR_create_context)
229     if (renderable & EGL_OPENGL_ES3_BIT_KHR)
230       renderable_values[i++] = "OpenGL ES 3.x";
231 #endif
232     if (renderable & EGL_OPENVG_BIT)
233       renderable_values[i++] = "OpenVG";
234 
235     /* bad things have happened if this fails: we haven't allocated enough
236      * space to hold all the values */
237     g_assert (i < MAX_RENDERABLE);
238 
239     renderable_str = g_strjoinv ("|", (char **) renderable_values);
240     GST_DEBUG_OBJECT (egl, "Renderable for %s", renderable_str);
241     g_free (renderable_str);
242 #undef MAX_RENDERABLE
243   }
244 
245   {
246 #define MAX_SURFACE 8
247     int surface, i = 0;
248     const char *surface_values[MAX_SURFACE] = { NULL, };
249     char *surface_str = NULL;
250 
251     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SURFACE_TYPE,
252             &surface))
253       return;
254 
255     if (surface & EGL_WINDOW_BIT)
256       surface_values[i++] = "window";
257     if (surface & EGL_PBUFFER_BIT)
258       surface_values[i++] = "pbuffer";
259     if (surface & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)
260       surface_values[i++] = "multisample-resolve-box";
261     if (surface & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
262       surface_values[i++] = "swap-behaviour-preserved";
263     if (surface & EGL_VG_ALPHA_FORMAT_PRE_BIT)
264       surface_values[i++] = "vg-alpha-format-pre";
265     if (surface & EGL_VG_COLORSPACE_LINEAR_BIT)
266       surface_values[i++] = "vg-colorspace-linear";
267 
268     /* bad things have happened if this fails: we haven't allocated enough
269      * space to hold all the values */
270     g_assert (i < MAX_SURFACE);
271 
272     surface_str = g_strjoinv ("|", (char **) surface_values);
273     GST_DEBUG_OBJECT (egl, "Surface for %s", surface_str);
274     g_free (surface_str);
275 #undef MAX_RENDERABLE
276   }
277 
278   {
279 #define MAX_CAVEAT 8
280     int caveat, i = 0;
281     const char *caveat_values[MAX_CAVEAT] = { NULL, };
282     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_CONFIG_CAVEAT,
283             &caveat))
284       return;
285     if (caveat == EGL_SLOW_CONFIG) {
286       caveat_values[i++] = "slow";
287     } else if (caveat == EGL_NON_CONFORMANT_CONFIG) {
288       caveat_values[i++] = "non-conformant";
289     }
290     if (i > 0) {
291       char *caveat_str = g_strjoinv ("|", (char **) caveat_values);
292       GST_DEBUG_OBJECT (egl, "Advertised as %s", caveat_str);
293       g_free (caveat_str);
294     }
295 #undef MAX_CAVEAT
296   }
297 
298   if (!eglGetConfigAttrib (egl->egl_display, config, EGL_COLOR_BUFFER_TYPE,
299           &buffer_type))
300     return;
301   if (buffer_type == EGL_RGB_BUFFER) {
302     int red, blue, green, alpha;
303 
304     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_RED_SIZE, &red))
305       return;
306     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_GREEN_SIZE, &green))
307       return;
308     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_BLUE_SIZE, &blue))
309       return;
310     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_ALPHA_SIZE, &alpha))
311       return;
312 
313     GST_DEBUG_OBJECT (egl, "[R, G, B, A] = [%i, %i, %i, %i]", red, green, blue,
314         alpha);
315   } else if (buffer_type == EGL_LUMINANCE_BUFFER) {
316     int luminance, alpha;
317     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_LUMINANCE_SIZE,
318             &luminance))
319       return;
320     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_ALPHA_SIZE, &alpha))
321       return;
322     GST_DEBUG_OBJECT (egl, "[L, A] = [%i, %i]", luminance, alpha);
323   } else {
324     GST_WARNING_OBJECT (egl, "unknown EGL_COLOR_BUFFER_TYPE value %x",
325         buffer_type);
326     return;
327   }
328   {
329     int depth, stencil;
330     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_DEPTH_SIZE, &depth))
331       return;
332     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_STENCIL_SIZE,
333             &stencil))
334       return;
335     GST_DEBUG_OBJECT (egl, "[D, S] = [%i, %i]", depth, stencil);
336   }
337   {
338     int min, max;
339 
340     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MIN_SWAP_INTERVAL,
341             &min))
342       return;
343     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_SWAP_INTERVAL,
344             &max))
345       return;
346     GST_DEBUG_OBJECT (egl, "Swap interval range is [%i, %i]", min, max);
347   }
348   {
349     int width, height, pixels;
350 
351     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_WIDTH,
352             &width))
353       return;
354     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_HEIGHT,
355             &height))
356       return;
357     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_MAX_PBUFFER_PIXELS,
358             &pixels))
359       return;
360     GST_DEBUG_OBJECT (egl,
361         "PBuffer maximum dimensions are [%i, %i]. Max pixels are %i", width,
362         height, pixels);
363   }
364   {
365     int sample_buffers, samples_per_pixel;
366 
367     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SAMPLE_BUFFERS,
368             &sample_buffers))
369       return;
370     if (!eglGetConfigAttrib (egl->egl_display, config, EGL_SAMPLES,
371             &samples_per_pixel))
372       return;
373     GST_DEBUG_OBJECT (egl, "Multisample buffers: %i and Samples per pixel: %i",
374         sample_buffers, samples_per_pixel);
375   }
376 }
377 
378 static void
gst_gl_context_egl_dump_all_configs(GstGLContextEGL * egl)379 gst_gl_context_egl_dump_all_configs (GstGLContextEGL * egl)
380 {
381   int i, n;
382   EGLConfig *configs;
383 
384   if (!eglGetConfigs (egl->egl_display, NULL, 0, &n)) {
385     GST_WARNING_OBJECT (egl, "Failed to get number of EGLConfig's");
386     return;
387   }
388 
389   configs = g_new0 (EGLConfig, n);
390   if (!eglGetConfigs (egl->egl_display, configs, n, &n)) {
391     GST_WARNING_OBJECT (egl, "Failed to get the list of EGLConfig's");
392     goto out;
393   }
394 
395   for (i = 0; i < n; i++)
396     gst_gl_context_egl_dump_config (egl, configs[i]);
397 
398 out:
399   g_free (configs);
400 }
401 
402 static gboolean
gst_gl_context_egl_choose_config(GstGLContextEGL * egl,GstGLAPI gl_api,gint major,GError ** error)403 gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api,
404     gint major, GError ** error)
405 {
406   gboolean create_context;
407   EGLint numConfigs;
408   gint i = 0;
409   EGLint config_attrib[20];
410   EGLint egl_api = 0;
411 
412   create_context =
413       gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
414   /* silence unused warnings */
415   (void) create_context;
416 
417   if (gl_api & GST_GL_API_GLES2) {
418     if (major == 3) {
419 #if defined(EGL_KHR_create_context)
420       if (create_context) {
421         egl_api = EGL_OPENGL_ES3_BIT_KHR;
422       } else
423 #endif
424       {
425         return FALSE;
426       }
427     } else {
428       egl_api = EGL_OPENGL_ES2_BIT;
429     }
430   } else
431     egl_api = EGL_OPENGL_BIT;
432 
433   config_attrib[i++] = EGL_SURFACE_TYPE;
434   config_attrib[i++] = EGL_WINDOW_BIT;
435   config_attrib[i++] = EGL_RENDERABLE_TYPE;
436   config_attrib[i++] = egl_api;
437 #if defined(USE_EGL_RPI) && GST_GL_HAVE_WINDOW_WAYLAND
438   /* The configurations with a=0 seems to be buggy whereas
439    * it works when using dispmanx directly */
440   config_attrib[i++] = EGL_ALPHA_SIZE;
441   config_attrib[i++] = 1;
442 #endif
443   config_attrib[i++] = EGL_DEPTH_SIZE;
444   config_attrib[i++] = 16;
445   config_attrib[i++] = EGL_RED_SIZE;
446   config_attrib[i++] = 1;
447   config_attrib[i++] = EGL_GREEN_SIZE;
448   config_attrib[i++] = 1;
449   config_attrib[i++] = EGL_BLUE_SIZE;
450   config_attrib[i++] = 1;
451   config_attrib[i++] = EGL_NONE;
452 
453   if (eglChooseConfig (egl->egl_display, config_attrib,
454           &egl->egl_config, 1, &numConfigs)) {
455     GST_INFO ("config set: %" G_GUINTPTR_FORMAT ", %u",
456         (guintptr) egl->egl_config, (unsigned int) numConfigs);
457   } else {
458     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
459         "Failed to set window configuration: %s",
460         gst_egl_get_error_string (eglGetError ()));
461     goto failure;
462   }
463 
464   GST_DEBUG_OBJECT (egl, "chosen EGLConfig");
465   gst_gl_context_egl_dump_config (egl, egl->egl_config);
466 
467   return TRUE;
468 
469 failure:
470   return FALSE;
471 }
472 
473 static EGLContext
_create_context_with_flags(GstGLContextEGL * egl,EGLContext share_context,GstGLAPI gl_api,gint major,gint minor,gint contextFlags,gint profileMask)474 _create_context_with_flags (GstGLContextEGL * egl, EGLContext share_context,
475     GstGLAPI gl_api, gint major, gint minor, gint contextFlags,
476     gint profileMask)
477 {
478   gboolean create_context;
479 #define N_ATTRIBS 20
480   gint attribs[N_ATTRIBS];
481   gint n = 0;
482 
483   /* fail creation of apis/versions/flags that require EGL_KHR_create_context
484    * if the extension doesn't exist, namely:0
485    *
486    * - profile mask
487    * - context flags
488    * - GL3 > 3.1
489    * - GLES2 && minor > 0
490    */
491   create_context =
492       gst_gl_check_extension ("EGL_KHR_create_context", egl->egl_exts);
493   (void) create_context;
494   if (!create_context && (profileMask || contextFlags
495           || ((gl_api & GST_GL_API_OPENGL3)
496               && GST_GL_CHECK_GL_VERSION (major, minor, 3, 2))
497           || ((gl_api & GST_GL_API_GLES2) && minor > 0))) {
498     return 0;
499   }
500 
501   GST_DEBUG_OBJECT (egl, "attempting to create OpenGL%s context version %d.%d "
502       "flags %x profile %x", gl_api & GST_GL_API_GLES2 ? " ES" : "", major,
503       minor, contextFlags, profileMask);
504 
505 #if defined(EGL_KHR_create_context)
506   if (create_context) {
507     if (major) {
508       attribs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR;
509       attribs[n++] = major;
510     }
511     if (minor) {
512       attribs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR;
513       attribs[n++] = minor;
514     }
515     if (contextFlags) {
516       attribs[n++] = EGL_CONTEXT_FLAGS_KHR;
517       attribs[n++] = contextFlags;
518     }
519     if (profileMask) {
520       attribs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
521       attribs[n++] = profileMask;
522     }
523   } else
524 #endif
525   {
526     attribs[n++] = EGL_CONTEXT_CLIENT_VERSION;
527     attribs[n++] = major;
528   }
529   attribs[n++] = EGL_NONE;
530 
531   g_assert (n < N_ATTRIBS);
532 #undef N_ATTRIBS
533 
534   return eglCreateContext (egl->egl_display, egl->egl_config, share_context,
535       attribs);
536 }
537 
538 static gboolean
gst_gl_context_egl_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)539 gst_gl_context_egl_create_context (GstGLContext * context,
540     GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
541 {
542   GstGLContextEGL *egl;
543   GstGLWindow *window = NULL;
544   guintptr window_handle = 0;
545   EGLint egl_major;
546   EGLint egl_minor;
547   gboolean need_surface = TRUE;
548   guintptr external_gl_context = 0;
549   guintptr egl_display;
550 
551   egl = GST_GL_CONTEXT_EGL (context);
552   window = gst_gl_context_get_window (context);
553 
554   GST_DEBUG_OBJECT (context, "Creating EGL context");
555 
556   if (other_context) {
557     if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_EGL) {
558       g_set_error (error, GST_GL_CONTEXT_ERROR,
559           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
560           "Cannot share context with non-EGL context");
561       goto failure;
562     }
563     external_gl_context = gst_gl_context_get_gl_context (other_context);
564   }
565 
566   if ((gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2)) ==
567       GST_GL_API_NONE) {
568     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
569         "EGL supports opengl or gles2");
570     goto failure;
571   }
572 
573   if (!egl->display_egl) {
574     GstGLDisplay *display = gst_gl_context_get_display (context);
575 
576     egl->display_egl = gst_gl_display_egl_from_gl_display (display);
577     if (!egl->display_egl) {
578       g_set_error (error, GST_GL_CONTEXT_ERROR,
579           GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
580           "Failed to create EGLDisplay from native display");
581       gst_object_unref (display);
582       goto failure;
583     }
584 
585     gst_object_unref (display);
586   }
587 
588   egl_display = gst_gl_display_get_handle (GST_GL_DISPLAY (egl->display_egl));
589   egl->egl_display = (EGLDisplay) egl_display;
590 
591   if (eglInitialize (egl->egl_display, &egl_major, &egl_minor)) {
592     GST_INFO ("egl initialized, version: %d.%d", egl_major, egl_minor);
593   } else {
594     g_set_error (error, GST_GL_CONTEXT_ERROR,
595         GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
596         "Failed to initialize egl: %s",
597         gst_egl_get_error_string (eglGetError ()));
598     goto failure;
599   }
600 
601   egl->egl_exts = eglQueryString (egl->egl_display, EGL_EXTENSIONS);
602 
603   gst_gl_context_egl_dump_all_configs (egl);
604 
605   if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) {
606     GstGLAPI chosen_gl_api = 0;
607     gint i;
608 
609     /* egl + opengl only available with EGL 1.4+ */
610     if (egl_major == 1 && egl_minor <= 3) {
611       if ((gl_api & ~GST_GL_API_OPENGL) == GST_GL_API_NONE) {
612         g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_OLD_LIBS,
613             "EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)",
614             egl_major, egl_minor);
615         goto failure;
616       } else {
617         GST_WARNING
618             ("EGL version (%i.%i) too old for OpenGL support, (needed at least 1.4)",
619             egl_major, egl_minor);
620         if (gl_api & GST_GL_API_GLES2) {
621           goto try_gles2;
622         } else {
623           g_set_error (error, GST_GL_CONTEXT_ERROR,
624               GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
625               "Failed to choose a suitable OpenGL API");
626           goto failure;
627         }
628       }
629     }
630 
631     if (!eglBindAPI (EGL_OPENGL_API)) {
632       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
633           "Failed to bind OpenGL API: %s",
634           gst_egl_get_error_string (eglGetError ()));
635       goto failure;
636     }
637 
638     GST_INFO ("Bound OpenGL");
639 
640     /* api, version only matters for gles */
641     if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_OPENGL, 0, error)) {
642       g_assert (error == NULL || *error != NULL);
643       goto failure;
644     }
645 
646     for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
647       gint profileMask = 0;
648       gint contextFlags = 0;
649 
650       if (GST_GL_CHECK_GL_VERSION (opengl_versions[i].major,
651               opengl_versions[i].minor, 3, 2)) {
652         /* skip gl3 contexts if requested */
653         if ((gl_api & GST_GL_API_OPENGL3) == 0)
654           continue;
655 
656         chosen_gl_api = GST_GL_API_OPENGL3;
657 #if defined(EGL_KHR_create_context)
658         profileMask |= EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
659         contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
660 #endif
661       } else if (opengl_versions[i].major == 3 && opengl_versions[i].minor == 1) {
662         /* skip 3.1, the implementation is free to give us either a core or a
663          * compatibility context (we have no say) */
664         continue;
665       } else {
666         /* skip legacy contexts if requested */
667         if ((gl_api & GST_GL_API_OPENGL) == 0)
668           continue;
669 
670         chosen_gl_api = GST_GL_API_OPENGL;
671       }
672 
673       egl->egl_context =
674           _create_context_with_flags (egl, (EGLContext) external_gl_context,
675           chosen_gl_api, opengl_versions[i].major,
676           opengl_versions[i].minor, contextFlags, profileMask);
677 
678       if (egl->egl_context)
679         break;
680 
681 #if defined(EGL_KHR_create_context)
682       profileMask &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
683 
684       egl->egl_context =
685           _create_context_with_flags (egl, (EGLContext) external_gl_context,
686           chosen_gl_api, opengl_versions[i].major,
687           opengl_versions[i].minor, contextFlags, profileMask);
688 
689       if (egl->egl_context)
690         break;
691 #endif
692     }
693 
694     egl->gl_api = chosen_gl_api;
695   } else if (gl_api & GST_GL_API_GLES2) {
696     gint i;
697 
698   try_gles2:
699     if (!eglBindAPI (EGL_OPENGL_ES_API)) {
700       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
701           "Failed to bind OpenGL|ES API: %s",
702           gst_egl_get_error_string (eglGetError ()));
703       goto failure;
704     }
705 
706     GST_INFO ("Bound OpenGL|ES");
707 
708     for (i = 0; i < G_N_ELEMENTS (gles2_versions); i++) {
709       gint profileMask = 0;
710       gint contextFlags = 0;
711       guint maj = gles2_versions[i].major;
712       guint min = gles2_versions[i].minor;
713 
714       if (!gst_gl_context_egl_choose_config (egl, GST_GL_API_GLES2, maj, error)) {
715         GST_DEBUG_OBJECT (context, "Failed to choose a GLES%d config: %s",
716             maj, error && *error ? (*error)->message : "Unknown");
717         g_clear_error (error);
718         continue;
719       }
720 #if defined(EGL_KHR_create_context)
721       /* try a debug context */
722       contextFlags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
723 
724       egl->egl_context =
725           _create_context_with_flags (egl, (EGLContext) external_gl_context,
726           GST_GL_API_GLES2, maj, min, contextFlags, profileMask);
727 
728       if (egl->egl_context)
729         break;
730 
731       /* try without a debug context */
732       contextFlags &= ~EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
733 #endif
734 
735       egl->egl_context =
736           _create_context_with_flags (egl, (EGLContext) external_gl_context,
737           GST_GL_API_GLES2, maj, min, contextFlags, profileMask);
738 
739       if (egl->egl_context)
740         break;
741     }
742     egl->gl_api = GST_GL_API_GLES2;
743   }
744 
745   if (egl->egl_context != EGL_NO_CONTEXT) {
746     GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT,
747         (guintptr) egl->egl_context);
748   } else {
749     g_set_error (error, GST_GL_CONTEXT_ERROR,
750         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
751         "Failed to create a OpenGL context: %s",
752         gst_egl_get_error_string (eglGetError ()));
753     goto failure;
754   }
755   /* FIXME do we want a window vfunc ? */
756 #if GST_GL_HAVE_WINDOW_X11
757   if (GST_IS_GL_WINDOW_X11 (context->window)) {
758     gst_gl_window_x11_create_window ((GstGLWindowX11 *) context->window);
759   }
760 #endif
761 
762   if (other_context == NULL) {
763     /* FIXME: fails to show two outputs at all.  We need a property/option for
764      * glimagesink to say its a visible context */
765 #if GST_GL_HAVE_WINDOW_WAYLAND
766     if (GST_IS_GL_WINDOW_WAYLAND_EGL (context->window)) {
767       gst_gl_window_wayland_egl_create_window ((GstGLWindowWaylandEGL *)
768           context->window);
769     }
770 #endif
771 #if GST_GL_HAVE_WINDOW_WIN32
772     if (GST_IS_GL_WINDOW_WIN32 (context->window)) {
773       gst_gl_window_win32_create_window ((GstGLWindowWin32 *) context->window);
774     }
775 #endif
776 #if GST_GL_HAVE_WINDOW_DISPMANX
777     if (GST_IS_GL_WINDOW_DISPMANX_EGL (context->window)) {
778       gst_gl_window_dispmanx_egl_create_window ((GstGLWindowDispmanxEGL *)
779           context->window);
780     }
781 #endif
782 #if GST_GL_HAVE_WINDOW_GBM
783     if (GST_IS_GL_WINDOW_GBM_EGL (context->window)) {
784       gst_gl_window_gbm_egl_create_window ((GstGLWindowGBMEGL *)
785           context->window);
786     }
787 #endif
788   }
789 
790   if (window)
791     window_handle = gst_gl_window_get_window_handle (window);
792 
793   if (window_handle) {
794     GST_DEBUG ("Creating EGLSurface from window_handle %p",
795         (void *) window_handle);
796     egl->egl_surface =
797         eglCreateWindowSurface (egl->egl_display, egl->egl_config,
798         (EGLNativeWindowType) window_handle, NULL);
799     /* Store window handle for later comparision */
800     egl->window_handle = window_handle;
801   } else if (!gst_gl_check_extension ("EGL_KHR_surfaceless_context",
802           egl->egl_exts)) {
803     EGLint surface_attrib[7];
804     gint j = 0;
805 
806     GST_DEBUG ("Surfaceless context, creating PBufferSurface");
807     /* FIXME: Width/height doesn't seem to matter but we can't leave them
808      * at 0, otherwise X11 complains about BadValue */
809     surface_attrib[j++] = EGL_WIDTH;
810     surface_attrib[j++] = 1;
811     surface_attrib[j++] = EGL_HEIGHT;
812     surface_attrib[j++] = 1;
813     surface_attrib[j++] = EGL_LARGEST_PBUFFER;
814     surface_attrib[j++] = EGL_TRUE;
815     surface_attrib[j++] = EGL_NONE;
816 
817     egl->egl_surface =
818         eglCreatePbufferSurface (egl->egl_display, egl->egl_config,
819         surface_attrib);
820   } else {
821     GST_DEBUG ("No surface/handle !");
822     egl->egl_surface = EGL_NO_SURFACE;
823     need_surface = FALSE;
824   }
825 
826   if (need_surface) {
827     if (egl->egl_surface != EGL_NO_SURFACE) {
828       GST_INFO ("surface created");
829     } else {
830       g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
831           "Failed to create window surface: %s",
832           gst_egl_get_error_string (eglGetError ()));
833       goto failure;
834     }
835   }
836   egl->egl_major = egl_major;
837   egl->egl_minor = egl_minor;
838 
839   if (window)
840     gst_object_unref (window);
841 
842   return TRUE;
843 
844 failure:
845   if (window)
846     gst_object_unref (window);
847 
848   return FALSE;
849 }
850 
851 static void
gst_gl_context_egl_destroy_context(GstGLContext * context)852 gst_gl_context_egl_destroy_context (GstGLContext * context)
853 {
854   GstGLContextEGL *egl;
855 
856   egl = GST_GL_CONTEXT_EGL (context);
857 
858   gst_gl_context_egl_activate (context, FALSE);
859 
860   if (egl->egl_surface) {
861     eglDestroySurface (egl->egl_display, egl->egl_surface);
862     egl->egl_surface = EGL_NO_SURFACE;
863   }
864 
865   if (egl->egl_context) {
866     eglDestroyContext (egl->egl_display, egl->egl_context);
867     egl->egl_context = NULL;
868   }
869   egl->window_handle = 0;
870 
871   eglReleaseThread ();
872 
873   if (egl->display_egl) {
874     gst_object_unref (egl->display_egl);
875     egl->display_egl = NULL;
876   }
877 }
878 
879 static gboolean
gst_gl_context_egl_activate(GstGLContext * context,gboolean activate)880 gst_gl_context_egl_activate (GstGLContext * context, gboolean activate)
881 {
882   GstGLContextEGL *egl;
883   gboolean result;
884 
885   egl = GST_GL_CONTEXT_EGL (context);
886 
887   if (activate) {
888     GstGLWindow *window = gst_gl_context_get_window (context);
889     guintptr handle = 0;
890     /* Check if the backing handle changed */
891     if (window) {
892       handle = gst_gl_window_get_window_handle (window);
893       gst_object_unref (window);
894     }
895     if (handle && handle != egl->window_handle) {
896       GST_DEBUG_OBJECT (context,
897           "Handle changed (have:%p, now:%p), switching surface",
898           (void *) egl->window_handle, (void *) handle);
899       if (egl->egl_surface) {
900         result = eglDestroySurface (egl->egl_display, egl->egl_surface);
901         egl->egl_surface = EGL_NO_SURFACE;
902         if (!result) {
903           GST_ERROR_OBJECT (context, "Failed to destroy old window surface: %s",
904               gst_egl_get_error_string (eglGetError ()));
905           goto done;
906         }
907       }
908       egl->egl_surface =
909           eglCreateWindowSurface (egl->egl_display, egl->egl_config,
910           (EGLNativeWindowType) handle, NULL);
911       egl->window_handle = handle;
912 
913       if (egl->egl_surface == EGL_NO_SURFACE) {
914         GST_ERROR_OBJECT (context, "Failed to create window surface: %s",
915             gst_egl_get_error_string (eglGetError ()));
916         result = FALSE;
917         goto done;
918       }
919     }
920     result = eglMakeCurrent (egl->egl_display, egl->egl_surface,
921         egl->egl_surface, egl->egl_context);
922   } else {
923     result = eglMakeCurrent (egl->egl_display, EGL_NO_SURFACE,
924         EGL_NO_SURFACE, EGL_NO_CONTEXT);
925   }
926 
927   if (!result) {
928     GST_ERROR_OBJECT (context,
929         "Failed to bind context to the current rendering thread: %s",
930         gst_egl_get_error_string (eglGetError ()));
931   }
932 
933 done:
934   return result;
935 }
936 
937 static guintptr
gst_gl_context_egl_get_gl_context(GstGLContext * context)938 gst_gl_context_egl_get_gl_context (GstGLContext * context)
939 {
940   return (guintptr) GST_GL_CONTEXT_EGL (context)->egl_context;
941 }
942 
943 static void
gst_gl_context_egl_swap_buffers(GstGLContext * context)944 gst_gl_context_egl_swap_buffers (GstGLContext * context)
945 {
946   GstGLContextEGL *egl;
947 
948   egl = GST_GL_CONTEXT_EGL (context);
949 
950   eglSwapBuffers (egl->egl_display, egl->egl_surface);
951 }
952 
953 static GstGLAPI
gst_gl_context_egl_get_gl_api(GstGLContext * context)954 gst_gl_context_egl_get_gl_api (GstGLContext * context)
955 {
956   return GST_GL_CONTEXT_EGL (context)->gl_api;
957 }
958 
959 static GstGLPlatform
gst_gl_context_egl_get_gl_platform(GstGLContext * context)960 gst_gl_context_egl_get_gl_platform (GstGLContext * context)
961 {
962   return GST_GL_PLATFORM_EGL;
963 }
964 
965 static GModule *module_egl;
966 
967 static gpointer
load_egl_module(gpointer user_data)968 load_egl_module (gpointer user_data)
969 {
970 #ifdef GST_GL_LIBEGL_MODULE_NAME
971   module_egl = g_module_open (GST_GL_LIBEGL_MODULE_NAME, G_MODULE_BIND_LAZY);
972 #else
973   /* On Linux the .so is only in -dev packages, try with a real soname
974    * Proper compilers will optimize away the strcmp */
975   if (g_strcmp0 (G_MODULE_SUFFIX, "so") == 0)
976     module_egl = g_module_open ("libEGL.so.1", G_MODULE_BIND_LAZY);
977 
978   /* This automatically handles the suffix and even .la files */
979   if (!module_egl)
980     module_egl = g_module_open ("libEGL", G_MODULE_BIND_LAZY);
981 #endif
982 
983   return NULL;
984 }
985 
986 gpointer
gst_gl_context_egl_get_proc_address(GstGLAPI gl_api,const gchar * name)987 gst_gl_context_egl_get_proc_address (GstGLAPI gl_api, const gchar * name)
988 {
989   gpointer result = NULL;
990   static GOnce g_once = G_ONCE_INIT;
991 
992 #ifdef __APPLE__
993 #if GST_GL_HAVE_OPENGL && !defined(GST_GL_LIBGL_MODULE_NAME)
994   if (!result && (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3))) {
995     static GModule *module_opengl = NULL;
996     if (g_once_init_enter (&module_opengl)) {
997       GModule *setup_module_opengl =
998           g_module_open ("libGL.dylib", G_MODULE_BIND_LAZY);
999       g_once_init_leave (&module_opengl, setup_module_opengl);
1000     }
1001     if (module_opengl)
1002       g_module_symbol (module_opengl, name, &result);
1003   }
1004 #endif
1005 #if GST_GL_HAVE_GLES2 && !defined(GST_GL_LIBGLESV2_MODULE_NAME)
1006   if (!result && (gl_api & (GST_GL_API_GLES2))) {
1007     static GModule *module_gles2 = NULL;
1008     if (g_once_init_enter (&module_gles2)) {
1009       GModule *setup_module_gles2 =
1010           g_module_open ("libGLESv2.dylib", G_MODULE_BIND_LAZY);
1011       g_once_init_leave (&module_gles2, setup_module_gles2);
1012     }
1013     if (module_gles2)
1014       g_module_symbol (module_gles2, name, &result);
1015   }
1016 #endif
1017 #endif // __APPLE__
1018 
1019   if (!result)
1020     result = gst_gl_context_default_get_proc_address (gl_api, name);
1021 
1022   g_once (&g_once, load_egl_module, NULL);
1023 
1024   if (!result && module_egl) {
1025     g_module_symbol (module_egl, name, &result);
1026   }
1027 
1028   /* FIXME: On Android this returns wrong addresses for non-EGL functions */
1029 #if GST_GL_HAVE_WINDOW_ANDROID
1030   if (!result && g_str_has_prefix (name, "egl")) {
1031 #else
1032   if (!result) {
1033     result = eglGetProcAddress (name);
1034 #endif
1035   }
1036 
1037   return result;
1038 }
1039 
1040 static gboolean
1041 gst_gl_context_egl_check_feature (GstGLContext * context, const gchar * feature)
1042 {
1043   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1044 
1045   return gst_gl_check_extension (feature, context_egl->egl_exts);
1046 }
1047 
1048 guintptr
1049 gst_gl_context_egl_get_current_context (void)
1050 {
1051   return (guintptr) eglGetCurrentContext ();
1052 }
1053 
1054 static void
1055 gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
1056     gint * major, gint * minor)
1057 {
1058   GstGLContextEGL *context_egl = GST_GL_CONTEXT_EGL (context);
1059 
1060   *major = context_egl->egl_major;
1061   *minor = context_egl->egl_minor;
1062 }
1063