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