1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (C) 2016, 2017 Red Hat Inc.
5 * Copyright (C) 2018, 2019 DisplayLink (UK) Ltd.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 *
22 * Written by:
23 * Jonas Ådahl <jadahl@gmail.com>
24 */
25
26 #include "config.h"
27
28 #include <EGL/egl.h>
29 #include <EGL/eglext.h>
30 #include <EGL/eglmesaext.h>
31 #include <gio/gio.h>
32 #include <glib.h>
33 #include <glib-object.h>
34
35 #include "backends/meta-backend-private.h"
36 #include "backends/meta-egl.h"
37 #include "backends/meta-egl-ext.h"
38 #include "meta/util.h"
39
40 struct _MetaEgl
41 {
42 GObject parent;
43
44 PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
45
46 PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
47 PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
48
49 PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL;
50 PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;
51
52 PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
53 PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
54
55 PFNEGLGETOUTPUTLAYERSEXTPROC eglGetOutputLayersEXT;
56 PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC eglQueryOutputLayerAttribEXT;
57
58 PFNEGLCREATESTREAMKHRPROC eglCreateStreamKHR;
59 PFNEGLDESTROYSTREAMKHRPROC eglDestroyStreamKHR;
60 PFNEGLQUERYSTREAMKHRPROC eglQueryStreamKHR;
61
62 PFNEGLCREATESTREAMATTRIBNVPROC eglCreateStreamAttribNV;
63
64 PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC eglCreateStreamProducerSurfaceKHR;
65
66 PFNEGLSTREAMCONSUMEROUTPUTEXTPROC eglStreamConsumerOutputEXT;
67
68 PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC eglStreamConsumerGLTextureExternalKHR;
69
70 PFNEGLSTREAMCONSUMERACQUIREKHRPROC eglStreamConsumerAcquireKHR;
71 PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC eglStreamConsumerAcquireAttribNV;
72
73 };
74
G_DEFINE_TYPE(MetaEgl,meta_egl,G_TYPE_OBJECT)75 G_DEFINE_TYPE (MetaEgl, meta_egl, G_TYPE_OBJECT)
76
77 G_DEFINE_QUARK (-meta-egl-error-quark, meta_egl_error)
78
79 static const char *
80 get_egl_error_str (EGLint error_number)
81 {
82 switch (error_number)
83 {
84 case EGL_SUCCESS:
85 return "The last function succeeded without error.";
86 break;
87 case EGL_NOT_INITIALIZED:
88 return "EGL is not initialized, or could not be initialized, for the specified EGL display connection.";
89 break;
90 case EGL_BAD_ACCESS:
91 return "EGL cannot access a requested resource (for example a context is bound in another thread).";
92 break;
93 case EGL_BAD_ALLOC:
94 return "EGL failed to allocate resources for the requested operation.";
95 break;
96 case EGL_BAD_ATTRIBUTE:
97 return "An unrecognized attribute or attribute value was passed in the attribute list.";
98 break;
99 case EGL_BAD_CONTEXT:
100 return "An EGLContext argument does not name a valid EGL rendering context.";
101 break;
102 case EGL_BAD_CONFIG:
103 return "An EGLConfig argument does not name a valid EGL frame buffer configuration.";
104 break;
105 case EGL_BAD_CURRENT_SURFACE:
106 return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid.";
107 break;
108 case EGL_BAD_DISPLAY:
109 return "An EGLDisplay argument does not name a valid EGL display connection.";
110 break;
111 case EGL_BAD_SURFACE:
112 return "An EGLSurface argument does not name a valid surface (window, pixel buffer or pixmap) configured for GL rendering.";
113 break;
114 case EGL_BAD_MATCH:
115 return "Arguments are inconsistent (for example, a valid context requires buffers not supplied by a valid surface).";
116 break;
117 case EGL_BAD_PARAMETER:
118 return "One or more argument values are invalid.";
119 break;
120 case EGL_BAD_NATIVE_PIXMAP:
121 return "A NativePixmapType argument does not refer to a valid native pixmap.";
122 break;
123 case EGL_BAD_NATIVE_WINDOW:
124 return "A NativeWindowType argument does not refer to a valid native window.";
125 break;
126 case EGL_CONTEXT_LOST:
127 return "A power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering. ";
128 break;
129 case EGL_BAD_STREAM_KHR:
130 return "An EGLStreamKHR argument does not name a valid EGL stream.";
131 break;
132 case EGL_BAD_STATE_KHR:
133 return "An EGLStreamKHR argument is not in a valid state";
134 break;
135 case EGL_BAD_DEVICE_EXT:
136 return "An EGLDeviceEXT argument does not name a valid EGL device.";
137 break;
138 case EGL_BAD_OUTPUT_LAYER_EXT:
139 return "An EGLOutputLayerEXT argument does not name a valid EGL output layer.";
140 case EGL_RESOURCE_BUSY_EXT:
141 return "The operation could not be completed on the requested resource because it is temporary unavailable.";
142 default:
143 return "Unknown error";
144 break;
145 }
146 }
147
148 static void
set_egl_error(GError ** error)149 set_egl_error (GError **error)
150 {
151 EGLint error_number;
152 const char *error_str;
153
154 if (!error)
155 return;
156
157 error_number = eglGetError ();
158 error_str = get_egl_error_str (error_number);
159 g_set_error_literal (error, META_EGL_ERROR,
160 error_number,
161 error_str);
162 }
163
164 gboolean
meta_extensions_string_has_extensions_valist(const char * extensions_str,const char *** missing_extensions,const char * first_extension,va_list var_args)165 meta_extensions_string_has_extensions_valist (const char *extensions_str,
166 const char ***missing_extensions,
167 const char *first_extension,
168 va_list var_args)
169 {
170 char **extensions;
171 const char *extension;
172 size_t num_missing_extensions = 0;
173
174 if (missing_extensions)
175 *missing_extensions = NULL;
176
177 extensions = g_strsplit (extensions_str, " ", -1);
178
179 extension = first_extension;
180 while (extension)
181 {
182 if (!g_strv_contains ((const char * const *) extensions, extension))
183 {
184 num_missing_extensions++;
185 if (missing_extensions)
186 {
187 *missing_extensions = g_realloc_n (*missing_extensions,
188 num_missing_extensions + 1,
189 sizeof (const char *));
190 (*missing_extensions)[num_missing_extensions - 1] = extension;
191 (*missing_extensions)[num_missing_extensions] = NULL;
192 }
193 else
194 {
195 break;
196 }
197 }
198 extension = va_arg (var_args, char *);
199 }
200
201 g_strfreev (extensions);
202
203 return num_missing_extensions == 0;
204 }
205
206 gboolean
meta_egl_has_extensions(MetaEgl * egl,EGLDisplay display,const char *** missing_extensions,const char * first_extension,...)207 meta_egl_has_extensions (MetaEgl *egl,
208 EGLDisplay display,
209 const char ***missing_extensions,
210 const char *first_extension,
211 ...)
212 {
213 va_list var_args;
214 const char *extensions_str;
215 gboolean has_extensions;
216
217 extensions_str = (const char *) eglQueryString (display, EGL_EXTENSIONS);
218 if (!extensions_str)
219 {
220 g_warning ("Failed to query string: %s",
221 get_egl_error_str (eglGetError ()));
222 return FALSE;
223 }
224
225 va_start (var_args, first_extension);
226 has_extensions =
227 meta_extensions_string_has_extensions_valist (extensions_str,
228 missing_extensions,
229 first_extension,
230 var_args);
231 va_end (var_args);
232
233 return has_extensions;
234 }
235
236 gboolean
meta_egl_initialize(MetaEgl * egl,EGLDisplay display,GError ** error)237 meta_egl_initialize (MetaEgl *egl,
238 EGLDisplay display,
239 GError **error)
240 {
241 if (!eglInitialize (display, NULL, NULL))
242 {
243 set_egl_error (error);
244 return FALSE;
245 }
246
247 return TRUE;
248 }
249
250 gboolean
meta_egl_bind_api(MetaEgl * egl,EGLenum api,GError ** error)251 meta_egl_bind_api (MetaEgl *egl,
252 EGLenum api,
253 GError **error)
254 {
255 if (!eglBindAPI (api))
256 {
257 set_egl_error (error);
258 return FALSE;
259 }
260
261 return TRUE;
262 }
263
264 gpointer
meta_egl_get_proc_address(MetaEgl * egl,const char * procname,GError ** error)265 meta_egl_get_proc_address (MetaEgl *egl,
266 const char *procname,
267 GError **error)
268 {
269 gpointer func;
270
271 func = (gpointer) eglGetProcAddress (procname);
272 if (!func)
273 {
274 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
275 "Could not load symbol '%s': Not found",
276 procname);
277 return NULL;
278 }
279
280 return func;
281 }
282
283 gboolean
meta_egl_get_config_attrib(MetaEgl * egl,EGLDisplay display,EGLConfig config,EGLint attribute,EGLint * value,GError ** error)284 meta_egl_get_config_attrib (MetaEgl *egl,
285 EGLDisplay display,
286 EGLConfig config,
287 EGLint attribute,
288 EGLint *value,
289 GError **error)
290 {
291 if (!eglGetConfigAttrib (display,
292 config,
293 attribute,
294 value))
295 {
296 set_egl_error (error);
297 return FALSE;
298 }
299
300 return TRUE;
301 }
302
303 EGLConfig *
meta_egl_choose_all_configs(MetaEgl * egl,EGLDisplay display,const EGLint * attrib_list,EGLint * out_num_configs,GError ** error)304 meta_egl_choose_all_configs (MetaEgl *egl,
305 EGLDisplay display,
306 const EGLint *attrib_list,
307 EGLint *out_num_configs,
308 GError **error)
309 {
310 EGLint num_configs;
311 EGLConfig *configs;
312 EGLint num_matches;
313
314 if (!eglGetConfigs (display, NULL, 0, &num_configs))
315 {
316 set_egl_error (error);
317 return FALSE;
318 }
319
320 if (num_configs < 1)
321 {
322 g_set_error (error, G_IO_ERROR,
323 G_IO_ERROR_FAILED,
324 "No EGL configurations available");
325 return FALSE;
326 }
327
328 configs = g_new0 (EGLConfig, num_configs);
329
330 if (!eglChooseConfig (display, attrib_list, configs, num_configs, &num_matches))
331 {
332 g_free (configs);
333 set_egl_error (error);
334 return FALSE;
335 }
336
337 if (num_matches == 0)
338 {
339 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
340 "No matching EGL configs");
341 g_free (configs);
342 return NULL;
343 }
344
345 *out_num_configs = num_configs;
346 return configs;
347 }
348
349 gboolean
meta_egl_choose_first_config(MetaEgl * egl,EGLDisplay display,const EGLint * attrib_list,EGLConfig * chosen_config,GError ** error)350 meta_egl_choose_first_config (MetaEgl *egl,
351 EGLDisplay display,
352 const EGLint *attrib_list,
353 EGLConfig *chosen_config,
354 GError **error)
355 {
356 EGLint num_configs;
357 EGLConfig *configs;
358 EGLint num_matches;
359
360 if (!eglGetConfigs (display, NULL, 0, &num_configs))
361 {
362 set_egl_error (error);
363 return FALSE;
364 }
365
366 if (num_configs < 1)
367 {
368 g_set_error (error, G_IO_ERROR,
369 G_IO_ERROR_FAILED,
370 "No EGL configurations available");
371 return FALSE;
372 }
373
374 configs = g_new0 (EGLConfig, num_configs);
375
376 if (!eglChooseConfig (display, attrib_list, configs, num_configs, &num_matches))
377 {
378 g_free (configs);
379 set_egl_error (error);
380 return FALSE;
381 }
382
383 if (num_matches == 0)
384 {
385 g_free (configs);
386 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
387 "No matching EGLConfig found");
388 return FALSE;
389 }
390
391 /*
392 * We don't have any preference specified yet, so lets choose the first one.
393 */
394 *chosen_config = configs[0];
395
396 g_free (configs);
397
398 return TRUE;
399 }
400
401 EGLSurface
meta_egl_create_window_surface(MetaEgl * egl,EGLDisplay display,EGLConfig config,EGLNativeWindowType native_window_type,const EGLint * attrib_list,GError ** error)402 meta_egl_create_window_surface (MetaEgl *egl,
403 EGLDisplay display,
404 EGLConfig config,
405 EGLNativeWindowType native_window_type,
406 const EGLint *attrib_list,
407 GError **error)
408 {
409 EGLSurface surface;
410
411 surface = eglCreateWindowSurface (display, config,
412 native_window_type, attrib_list);
413 if (surface == EGL_NO_SURFACE)
414 {
415 set_egl_error (error);
416 return EGL_NO_SURFACE;
417 }
418
419 return surface;
420 }
421
422 EGLSurface
meta_egl_create_pbuffer_surface(MetaEgl * egl,EGLDisplay display,EGLConfig config,const EGLint * attrib_list,GError ** error)423 meta_egl_create_pbuffer_surface (MetaEgl *egl,
424 EGLDisplay display,
425 EGLConfig config,
426 const EGLint *attrib_list,
427 GError **error)
428 {
429 EGLSurface surface;
430
431 surface = eglCreatePbufferSurface (display, config, attrib_list);
432 if (surface == EGL_NO_SURFACE)
433 {
434 set_egl_error (error);
435 return EGL_NO_SURFACE;
436 }
437
438 return surface;
439 }
440
441 gboolean
meta_egl_destroy_surface(MetaEgl * egl,EGLDisplay display,EGLSurface surface,GError ** error)442 meta_egl_destroy_surface (MetaEgl *egl,
443 EGLDisplay display,
444 EGLSurface surface,
445 GError **error)
446 {
447 if (!eglDestroySurface (display, surface))
448 {
449 set_egl_error (error);
450 return FALSE;
451 }
452
453 return TRUE;
454 }
455
456 static gboolean
is_egl_proc_valid_real(void * proc,const char * proc_name,GError ** error)457 is_egl_proc_valid_real (void *proc,
458 const char *proc_name,
459 GError **error)
460 {
461 if (!proc)
462 {
463 g_set_error (error, G_IO_ERROR,
464 G_IO_ERROR_FAILED,
465 "EGL proc '%s' not resolved",
466 proc_name);
467 return FALSE;
468 }
469
470 return TRUE;
471 }
472
473 #define is_egl_proc_valid(proc, error) \
474 is_egl_proc_valid_real (proc, #proc, error)
475
476 EGLDisplay
meta_egl_get_platform_display(MetaEgl * egl,EGLenum platform,void * native_display,const EGLint * attrib_list,GError ** error)477 meta_egl_get_platform_display (MetaEgl *egl,
478 EGLenum platform,
479 void *native_display,
480 const EGLint *attrib_list,
481 GError **error)
482 {
483 EGLDisplay display;
484
485 if (!is_egl_proc_valid (egl->eglGetPlatformDisplayEXT, error))
486 return EGL_NO_DISPLAY;
487
488 display = egl->eglGetPlatformDisplayEXT (platform,
489 native_display,
490 attrib_list);
491 if (display == EGL_NO_DISPLAY)
492 {
493 set_egl_error (error);
494 return EGL_NO_DISPLAY;
495 }
496
497 return display;
498 }
499
500 gboolean
meta_egl_terminate(MetaEgl * egl,EGLDisplay display,GError ** error)501 meta_egl_terminate (MetaEgl *egl,
502 EGLDisplay display,
503 GError **error)
504 {
505 if (!eglTerminate (display))
506 {
507 set_egl_error (error);
508 return FALSE;
509 }
510
511 return TRUE;
512 }
513
514 EGLContext
meta_egl_create_context(MetaEgl * egl,EGLDisplay display,EGLConfig config,EGLContext share_context,const EGLint * attrib_list,GError ** error)515 meta_egl_create_context (MetaEgl *egl,
516 EGLDisplay display,
517 EGLConfig config,
518 EGLContext share_context,
519 const EGLint *attrib_list,
520 GError **error)
521 {
522 EGLContext context;
523
524 context = eglCreateContext (display, config, share_context, attrib_list);
525 if (context == EGL_NO_CONTEXT)
526 {
527 set_egl_error (error);
528 return EGL_NO_CONTEXT;
529 }
530
531 return context;
532 }
533
534 gboolean
meta_egl_destroy_context(MetaEgl * egl,EGLDisplay display,EGLContext context,GError ** error)535 meta_egl_destroy_context (MetaEgl *egl,
536 EGLDisplay display,
537 EGLContext context,
538 GError **error)
539 {
540 if (!eglDestroyContext (display, context))
541 {
542 set_egl_error (error);
543 return FALSE;
544 }
545
546 return TRUE;
547 }
548
549 EGLImageKHR
meta_egl_create_image(MetaEgl * egl,EGLDisplay display,EGLContext context,EGLenum target,EGLClientBuffer buffer,const EGLint * attrib_list,GError ** error)550 meta_egl_create_image (MetaEgl *egl,
551 EGLDisplay display,
552 EGLContext context,
553 EGLenum target,
554 EGLClientBuffer buffer,
555 const EGLint *attrib_list,
556 GError **error)
557 {
558 EGLImageKHR image;
559
560 if (!is_egl_proc_valid (egl->eglCreateImageKHR, error))
561 return EGL_NO_IMAGE_KHR;
562
563 image = egl->eglCreateImageKHR (display, context,
564 target, buffer, attrib_list);
565 if (image == EGL_NO_IMAGE_KHR)
566 {
567 set_egl_error (error);
568 return EGL_NO_IMAGE_KHR;
569 }
570
571 return image;
572 }
573
574 gboolean
meta_egl_destroy_image(MetaEgl * egl,EGLDisplay display,EGLImageKHR image,GError ** error)575 meta_egl_destroy_image (MetaEgl *egl,
576 EGLDisplay display,
577 EGLImageKHR image,
578 GError **error)
579 {
580 if (!is_egl_proc_valid (egl->eglDestroyImageKHR, error))
581 return FALSE;
582
583 if (!egl->eglDestroyImageKHR (display, image))
584 {
585 set_egl_error (error);
586 return FALSE;
587 }
588
589 return TRUE;
590 }
591
592 EGLImageKHR
meta_egl_create_dmabuf_image(MetaEgl * egl,EGLDisplay egl_display,unsigned int width,unsigned int height,uint32_t drm_format,uint32_t n_planes,const int * fds,const uint32_t * strides,const uint32_t * offsets,const uint64_t * modifiers,GError ** error)593 meta_egl_create_dmabuf_image (MetaEgl *egl,
594 EGLDisplay egl_display,
595 unsigned int width,
596 unsigned int height,
597 uint32_t drm_format,
598 uint32_t n_planes,
599 const int *fds,
600 const uint32_t *strides,
601 const uint32_t *offsets,
602 const uint64_t *modifiers,
603 GError **error)
604 {
605 EGLint attribs[37];
606 int atti = 0;
607
608 /* This requires the Mesa commit in
609 * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
610 * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
611 * Otherwise Mesa closes the fd behind our back and re-importing
612 * will fail.
613 * https://bugs.freedesktop.org/show_bug.cgi?id=76188
614 */
615
616 attribs[atti++] = EGL_WIDTH;
617 attribs[atti++] = width;
618 attribs[atti++] = EGL_HEIGHT;
619 attribs[atti++] = height;
620 attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
621 attribs[atti++] = drm_format;
622
623 if (n_planes > 0)
624 {
625 attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
626 attribs[atti++] = fds[0];
627 attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
628 attribs[atti++] = offsets[0];
629 attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
630 attribs[atti++] = strides[0];
631 if (modifiers)
632 {
633 attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
634 attribs[atti++] = modifiers[0] & 0xFFFFFFFF;
635 attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
636 attribs[atti++] = modifiers[0] >> 32;
637 }
638 }
639
640 if (n_planes > 1)
641 {
642 attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
643 attribs[atti++] = fds[1];
644 attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
645 attribs[atti++] = offsets[1];
646 attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
647 attribs[atti++] = strides[1];
648 if (modifiers)
649 {
650 attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT;
651 attribs[atti++] = modifiers[1] & 0xFFFFFFFF;
652 attribs[atti++] = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT;
653 attribs[atti++] = modifiers[1] >> 32;
654 }
655 }
656
657 if (n_planes > 2)
658 {
659 attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
660 attribs[atti++] = fds[2];
661 attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
662 attribs[atti++] = offsets[2];
663 attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
664 attribs[atti++] = strides[2];
665 if (modifiers)
666 {
667 attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT;
668 attribs[atti++] = modifiers[2] & 0xFFFFFFFF;
669 attribs[atti++] = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT;
670 attribs[atti++] = modifiers[2] >> 32;
671 }
672 }
673
674 attribs[atti++] = EGL_NONE;
675 g_assert (atti <= G_N_ELEMENTS (attribs));
676
677 return meta_egl_create_image (egl, egl_display, EGL_NO_CONTEXT,
678 EGL_LINUX_DMA_BUF_EXT, NULL,
679 attribs,
680 error);
681 }
682
683 gboolean
meta_egl_make_current(MetaEgl * egl,EGLDisplay display,EGLSurface draw,EGLSurface read,EGLContext context,GError ** error)684 meta_egl_make_current (MetaEgl *egl,
685 EGLDisplay display,
686 EGLSurface draw,
687 EGLSurface read,
688 EGLContext context,
689 GError **error)
690 {
691 if (!eglMakeCurrent (display, draw, read, context))
692 {
693 set_egl_error (error);
694 return FALSE;
695 }
696
697 return TRUE;
698 }
699
700 gboolean
meta_egl_swap_buffers(MetaEgl * egl,EGLDisplay display,EGLSurface surface,GError ** error)701 meta_egl_swap_buffers (MetaEgl *egl,
702 EGLDisplay display,
703 EGLSurface surface,
704 GError **error)
705 {
706 if (!eglSwapBuffers (display, surface))
707 {
708 set_egl_error (error);
709 return FALSE;
710 }
711
712 return TRUE;
713 }
714
715 gboolean
meta_egl_bind_wayland_display(MetaEgl * egl,EGLDisplay display,struct wl_display * wayland_display,GError ** error)716 meta_egl_bind_wayland_display (MetaEgl *egl,
717 EGLDisplay display,
718 struct wl_display *wayland_display,
719 GError **error)
720 {
721 if (!is_egl_proc_valid (egl->eglBindWaylandDisplayWL, error))
722 return FALSE;
723
724 if (!egl->eglBindWaylandDisplayWL (display, wayland_display))
725 {
726 set_egl_error (error);
727 return FALSE;
728 }
729
730 return TRUE;
731 }
732
733 gboolean
meta_egl_query_wayland_buffer(MetaEgl * egl,EGLDisplay display,struct wl_resource * buffer,EGLint attribute,EGLint * value,GError ** error)734 meta_egl_query_wayland_buffer (MetaEgl *egl,
735 EGLDisplay display,
736 struct wl_resource *buffer,
737 EGLint attribute,
738 EGLint *value,
739 GError **error)
740 {
741 if (!is_egl_proc_valid (egl->eglQueryWaylandBufferWL, error))
742 return FALSE;
743
744 if (!egl->eglQueryWaylandBufferWL (display, buffer, attribute, value))
745 {
746 set_egl_error (error);
747 return FALSE;
748 }
749
750 return TRUE;
751 }
752
753 gboolean
meta_egl_query_devices(MetaEgl * egl,EGLint max_devices,EGLDeviceEXT * devices,EGLint * num_devices,GError ** error)754 meta_egl_query_devices (MetaEgl *egl,
755 EGLint max_devices,
756 EGLDeviceEXT *devices,
757 EGLint *num_devices,
758 GError **error)
759 {
760 if (!is_egl_proc_valid (egl->eglQueryDevicesEXT, error))
761 return FALSE;
762
763 if (!egl->eglQueryDevicesEXT (max_devices,
764 devices,
765 num_devices))
766 {
767 set_egl_error (error);
768 return FALSE;
769 }
770
771 return TRUE;
772 }
773
774 const char *
meta_egl_query_device_string(MetaEgl * egl,EGLDeviceEXT device,EGLint name,GError ** error)775 meta_egl_query_device_string (MetaEgl *egl,
776 EGLDeviceEXT device,
777 EGLint name,
778 GError **error)
779 {
780 const char *device_string;
781
782 if (!is_egl_proc_valid (egl->eglQueryDeviceStringEXT, error))
783 return NULL;
784
785 device_string = egl->eglQueryDeviceStringEXT (device, name);
786 if (!device_string)
787 {
788 set_egl_error (error);
789 return NULL;
790 }
791
792 return device_string;
793 }
794
795 gboolean
meta_egl_egl_device_has_extensions(MetaEgl * egl,EGLDeviceEXT device,const char *** missing_extensions,const char * first_extension,...)796 meta_egl_egl_device_has_extensions (MetaEgl *egl,
797 EGLDeviceEXT device,
798 const char ***missing_extensions,
799 const char *first_extension,
800 ...)
801 {
802 va_list var_args;
803 const char *extensions_str;
804 gboolean has_extensions;
805 GError *error = NULL;
806
807 extensions_str = meta_egl_query_device_string (egl, device, EGL_EXTENSIONS,
808 &error);
809 if (!extensions_str)
810 {
811 g_warning ("Failed to query device string: %s", error->message);
812 g_error_free (error);
813 return FALSE;
814 }
815
816 va_start (var_args, first_extension);
817 has_extensions =
818 meta_extensions_string_has_extensions_valist (extensions_str,
819 missing_extensions,
820 first_extension,
821 var_args);
822 va_end (var_args);
823
824 return has_extensions;
825 }
826
827 gboolean
meta_egl_get_output_layers(MetaEgl * egl,EGLDisplay display,const EGLAttrib * attrib_list,EGLOutputLayerEXT * layers,EGLint max_layers,EGLint * num_layers,GError ** error)828 meta_egl_get_output_layers (MetaEgl *egl,
829 EGLDisplay display,
830 const EGLAttrib *attrib_list,
831 EGLOutputLayerEXT *layers,
832 EGLint max_layers,
833 EGLint *num_layers,
834 GError **error)
835 {
836 if (!is_egl_proc_valid (egl->eglGetOutputLayersEXT, error))
837 return FALSE;
838
839 if (!egl->eglGetOutputLayersEXT (display,
840 attrib_list,
841 layers,
842 max_layers,
843 num_layers))
844 {
845 set_egl_error (error);
846 return FALSE;
847 }
848
849 return TRUE;
850 }
851
852 gboolean
meta_egl_query_output_layer_attrib(MetaEgl * egl,EGLDisplay display,EGLOutputLayerEXT layer,EGLint attribute,EGLAttrib * value,GError ** error)853 meta_egl_query_output_layer_attrib (MetaEgl *egl,
854 EGLDisplay display,
855 EGLOutputLayerEXT layer,
856 EGLint attribute,
857 EGLAttrib *value,
858 GError **error)
859 {
860 if (!is_egl_proc_valid (egl->eglQueryOutputLayerAttribEXT, error))
861 return FALSE;
862
863 if (!egl->eglQueryOutputLayerAttribEXT (display, layer,
864 attribute, value))
865 {
866 set_egl_error (error);
867 return FALSE;
868 }
869
870 return TRUE;
871 }
872
873 EGLStreamKHR
meta_egl_create_stream(MetaEgl * egl,EGLDisplay display,const EGLint * attrib_list,GError ** error)874 meta_egl_create_stream (MetaEgl *egl,
875 EGLDisplay display,
876 const EGLint *attrib_list,
877 GError **error)
878 {
879 EGLStreamKHR stream;
880
881 if (!is_egl_proc_valid (egl->eglCreateStreamKHR, error))
882 return EGL_NO_STREAM_KHR;
883
884 stream = egl->eglCreateStreamKHR (display, attrib_list);
885 if (stream == EGL_NO_STREAM_KHR)
886 {
887 set_egl_error (error);
888 return EGL_NO_STREAM_KHR;
889 }
890
891 return stream;
892 }
893
894 gboolean
meta_egl_destroy_stream(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,GError ** error)895 meta_egl_destroy_stream (MetaEgl *egl,
896 EGLDisplay display,
897 EGLStreamKHR stream,
898 GError **error)
899 {
900 if (!is_egl_proc_valid (egl->eglDestroyStreamKHR, error))
901 return FALSE;
902
903 if (!egl->eglDestroyStreamKHR (display, stream))
904 {
905 set_egl_error (error);
906 return FALSE;
907 }
908
909 return TRUE;
910 }
911
912 gboolean
meta_egl_query_stream(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,EGLenum attribute,EGLint * value,GError ** error)913 meta_egl_query_stream (MetaEgl *egl,
914 EGLDisplay display,
915 EGLStreamKHR stream,
916 EGLenum attribute,
917 EGLint *value,
918 GError **error)
919 {
920 if (!is_egl_proc_valid (egl->eglQueryStreamKHR, error))
921 return FALSE;
922
923 if (!egl->eglQueryStreamKHR (display, stream, attribute, value))
924 {
925 set_egl_error (error);
926 return FALSE;
927 }
928
929 return TRUE;
930 }
931
932 EGLStreamKHR
meta_egl_create_stream_attrib(MetaEgl * egl,EGLDisplay display,const EGLAttrib * attrib_list,GError ** error)933 meta_egl_create_stream_attrib (MetaEgl *egl,
934 EGLDisplay display,
935 const EGLAttrib *attrib_list,
936 GError **error)
937 {
938 EGLStreamKHR stream;
939
940 if (!is_egl_proc_valid (egl->eglCreateStreamAttribNV, error))
941 return FALSE;
942
943 stream = egl->eglCreateStreamAttribNV (display, attrib_list);
944 if (stream == EGL_NO_STREAM_KHR)
945 {
946 set_egl_error (error);
947 return EGL_NO_STREAM_KHR;
948 }
949
950 return stream;
951 }
952
953 EGLSurface
meta_egl_create_stream_producer_surface(MetaEgl * egl,EGLDisplay display,EGLConfig config,EGLStreamKHR stream,const EGLint * attrib_list,GError ** error)954 meta_egl_create_stream_producer_surface (MetaEgl *egl,
955 EGLDisplay display,
956 EGLConfig config,
957 EGLStreamKHR stream,
958 const EGLint *attrib_list,
959 GError **error)
960 {
961 EGLSurface surface;
962
963 if (!is_egl_proc_valid (egl->eglCreateStreamProducerSurfaceKHR, error))
964 return EGL_NO_SURFACE;
965
966 surface = egl->eglCreateStreamProducerSurfaceKHR (display,
967 config,
968 stream,
969 attrib_list);
970 if (surface == EGL_NO_SURFACE)
971 {
972 set_egl_error (error);
973 return EGL_NO_SURFACE;
974 }
975
976 return surface;
977 }
978
979 gboolean
meta_egl_stream_consumer_output(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,EGLOutputLayerEXT layer,GError ** error)980 meta_egl_stream_consumer_output (MetaEgl *egl,
981 EGLDisplay display,
982 EGLStreamKHR stream,
983 EGLOutputLayerEXT layer,
984 GError **error)
985 {
986 if (!is_egl_proc_valid (egl->eglStreamConsumerOutputEXT, error))
987 return FALSE;
988
989 if (!egl->eglStreamConsumerOutputEXT (display, stream, layer))
990 {
991 set_egl_error (error);
992 return FALSE;
993 }
994
995 return TRUE;
996 }
997
998 gboolean
meta_egl_stream_consumer_acquire_attrib(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,EGLAttrib * attrib_list,GError ** error)999 meta_egl_stream_consumer_acquire_attrib (MetaEgl *egl,
1000 EGLDisplay display,
1001 EGLStreamKHR stream,
1002 EGLAttrib *attrib_list,
1003 GError **error)
1004 {
1005 if (!is_egl_proc_valid (egl->eglStreamConsumerAcquireAttribNV, error))
1006 return FALSE;
1007
1008 if (!egl->eglStreamConsumerAcquireAttribNV (display, stream, attrib_list))
1009 {
1010 set_egl_error (error);
1011 return FALSE;
1012 }
1013
1014 return TRUE;
1015 }
1016
1017 gboolean
meta_egl_stream_consumer_gl_texture_external(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,GError ** error)1018 meta_egl_stream_consumer_gl_texture_external (MetaEgl *egl,
1019 EGLDisplay display,
1020 EGLStreamKHR stream,
1021 GError **error)
1022 {
1023 if (!is_egl_proc_valid (egl->eglStreamConsumerGLTextureExternalKHR, error))
1024 return FALSE;
1025
1026 if (!egl->eglStreamConsumerGLTextureExternalKHR (display, stream))
1027 {
1028 set_egl_error (error);
1029 return FALSE;
1030 }
1031
1032 return TRUE;
1033 }
1034
1035 gboolean
meta_egl_stream_consumer_acquire(MetaEgl * egl,EGLDisplay display,EGLStreamKHR stream,GError ** error)1036 meta_egl_stream_consumer_acquire (MetaEgl *egl,
1037 EGLDisplay display,
1038 EGLStreamKHR stream,
1039 GError **error)
1040 {
1041 if (!is_egl_proc_valid (egl->eglStreamConsumerAcquireKHR, error))
1042 return FALSE;
1043
1044 if (!egl->eglStreamConsumerAcquireKHR (display, stream))
1045 {
1046 set_egl_error (error);
1047 return FALSE;
1048 }
1049
1050 return TRUE;
1051 }
1052
1053 #define GET_EGL_PROC_ADDR(proc) \
1054 egl->proc = (void *) eglGetProcAddress (#proc);
1055
1056 static void
meta_egl_constructed(GObject * object)1057 meta_egl_constructed (GObject *object)
1058 {
1059 MetaEgl *egl = META_EGL (object);
1060
1061 GET_EGL_PROC_ADDR (eglGetPlatformDisplayEXT);
1062
1063 GET_EGL_PROC_ADDR (eglCreateImageKHR);
1064 GET_EGL_PROC_ADDR (eglDestroyImageKHR);
1065
1066 GET_EGL_PROC_ADDR (eglBindWaylandDisplayWL);
1067 GET_EGL_PROC_ADDR (eglQueryWaylandBufferWL);
1068
1069 GET_EGL_PROC_ADDR (eglQueryDevicesEXT);
1070 GET_EGL_PROC_ADDR (eglQueryDeviceStringEXT);
1071
1072 GET_EGL_PROC_ADDR (eglGetOutputLayersEXT);
1073 GET_EGL_PROC_ADDR (eglQueryOutputLayerAttribEXT);
1074
1075 GET_EGL_PROC_ADDR (eglCreateStreamKHR);
1076 GET_EGL_PROC_ADDR (eglDestroyStreamKHR);
1077 GET_EGL_PROC_ADDR (eglQueryStreamKHR);
1078
1079 GET_EGL_PROC_ADDR (eglCreateStreamAttribNV);
1080
1081 GET_EGL_PROC_ADDR (eglCreateStreamProducerSurfaceKHR);
1082
1083 GET_EGL_PROC_ADDR (eglStreamConsumerOutputEXT);
1084
1085 GET_EGL_PROC_ADDR (eglStreamConsumerGLTextureExternalKHR);
1086
1087 GET_EGL_PROC_ADDR (eglStreamConsumerAcquireKHR);
1088 GET_EGL_PROC_ADDR (eglStreamConsumerAcquireAttribNV);
1089
1090 }
1091
1092 #undef GET_EGL_PROC_ADDR
1093
1094 static void
meta_egl_init(MetaEgl * egl)1095 meta_egl_init (MetaEgl *egl)
1096 {
1097 }
1098
1099 static void
meta_egl_class_init(MetaEglClass * klass)1100 meta_egl_class_init (MetaEglClass *klass)
1101 {
1102 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1103
1104 object_class->constructed = meta_egl_constructed;
1105 }
1106