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