• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2008 VMware, Inc.
4  * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5  * Copyright 2010-2011 LunarG, Inc.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sub license, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the
17  * next paragraph) shall be included in all copies or substantial portions
18  * of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  *
28  **************************************************************************/
29 
30 /**
31  * Functions related to EGLDisplay.
32  */
33 
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #ifdef _WIN32
38 #include <io.h>
39 #else
40 #include <unistd.h>
41 #endif
42 #include <fcntl.h>
43 #include "c11/threads.h"
44 #include "util/macros.h"
45 #include "util/os_file.h"
46 #include "util/u_atomic.h"
47 
48 #include "eglcontext.h"
49 #include "eglcurrent.h"
50 #include "egldevice.h"
51 #include "egldisplay.h"
52 #include "egldriver.h"
53 #include "eglglobals.h"
54 #include "eglimage.h"
55 #include "egllog.h"
56 #include "eglsurface.h"
57 #include "eglsync.h"
58 
59 /* Includes for _eglNativePlatformDetectNativeDisplay */
60 #ifdef HAVE_WAYLAND_PLATFORM
61 #include <wayland-client.h>
62 #endif
63 #ifdef HAVE_DRM_PLATFORM
64 #include <gbm.h>
65 #endif
66 #ifdef HAVE_WINDOWS_PLATFORM
67 #include <windows.h>
68 #endif
69 
70 /**
71  * Map build-system platform names to platform types.
72  */
73 static const struct {
74    _EGLPlatformType platform;
75    const char *name;
76 } egl_platforms[] = {
77    {_EGL_PLATFORM_X11, "x11"},
78    {_EGL_PLATFORM_XCB, "xcb"},
79    {_EGL_PLATFORM_WAYLAND, "wayland"},
80    {_EGL_PLATFORM_DRM, "drm"},
81    {_EGL_PLATFORM_ANDROID, "android"},
82    {_EGL_PLATFORM_HAIKU, "haiku"},
83    {_EGL_PLATFORM_SURFACELESS, "surfaceless"},
84    {_EGL_PLATFORM_DEVICE, "device"},
85    {_EGL_PLATFORM_WINDOWS, "windows"},
86    {_EGL_PLATFORM_OHOS, "ohos"},
87 };
88 
89 /**
90  * Return the native platform by parsing EGL_PLATFORM.
91  */
92 static _EGLPlatformType
_eglGetNativePlatformFromEnv(void)93 _eglGetNativePlatformFromEnv(void)
94 {
95    _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
96    const char *plat_name;
97    EGLint i;
98 
99    static_assert(ARRAY_SIZE(egl_platforms) == _EGL_NUM_PLATFORMS,
100                  "Missing platform");
101 
102    plat_name = getenv("EGL_PLATFORM");
103    /* try deprecated env variable */
104    if (!plat_name || !plat_name[0])
105       plat_name = getenv("EGL_DISPLAY");
106    if (!plat_name || !plat_name[0])
107       return _EGL_INVALID_PLATFORM;
108 
109    for (i = 0; i < ARRAY_SIZE(egl_platforms); i++) {
110       if (strcmp(egl_platforms[i].name, plat_name) == 0) {
111          plat = egl_platforms[i].platform;
112          break;
113       }
114    }
115 
116    if (plat == _EGL_INVALID_PLATFORM)
117       _eglLog(_EGL_WARNING, "invalid EGL_PLATFORM given");
118 
119    return plat;
120 }
121 
122 /**
123  * Try detecting native platform with the help of native display characteristics.
124  */
125 static _EGLPlatformType
_eglNativePlatformDetectNativeDisplay(void * nativeDisplay)126 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
127 {
128    if (nativeDisplay == EGL_DEFAULT_DISPLAY)
129       return _EGL_INVALID_PLATFORM;
130 
131 #ifdef HAVE_WINDOWS_PLATFORM
132    if (GetObjectType(nativeDisplay) == OBJ_DC)
133       return _EGL_PLATFORM_WINDOWS;
134 #endif
135 
136 #if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)
137    if (_eglPointerIsDereferenceable(nativeDisplay)) {
138       void *first_pointer = *(void **)nativeDisplay;
139 
140 #ifdef HAVE_WAYLAND_PLATFORM
141       /* wl_display is a wl_proxy, which is a wl_object.
142        * wl_object's first element points to the interfacetype. */
143       if (first_pointer == &wl_display_interface)
144          return _EGL_PLATFORM_WAYLAND;
145 #endif
146 
147 #ifdef HAVE_DRM_PLATFORM
148       /* gbm has a pointer to its constructor as first element. */
149       if (first_pointer == gbm_create_device)
150          return _EGL_PLATFORM_DRM;
151 #endif
152    }
153 #endif
154 
155    return _EGL_INVALID_PLATFORM;
156 }
157 
158 /**
159  * Return the native platform.  It is the platform of the EGL native types.
160  */
161 _EGLPlatformType
_eglGetNativePlatform(void * nativeDisplay)162 _eglGetNativePlatform(void *nativeDisplay)
163 {
164    _EGLPlatformType detected_platform = _eglGetNativePlatformFromEnv();
165    const char *detection_method = "environment";
166 
167    if (detected_platform == _EGL_INVALID_PLATFORM) {
168       detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
169       detection_method = "autodetected";
170    }
171 
172    if (detected_platform == _EGL_INVALID_PLATFORM) {
173       detected_platform = _EGL_NATIVE_PLATFORM;
174       detection_method = "build-time configuration";
175    }
176 
177    _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
178            egl_platforms[detected_platform].name, detection_method);
179 
180    return detected_platform;
181 }
182 
183 /**
184  * Finish display management.
185  */
186 void
_eglFiniDisplay(void)187 _eglFiniDisplay(void)
188 {
189    _EGLDisplay *dispList, *disp;
190 
191    /* atexit function is called with global mutex locked */
192    dispList = _eglGlobal.DisplayList;
193    while (dispList) {
194       EGLint i;
195 
196       /* pop list head */
197       disp = dispList;
198       dispList = dispList->Next;
199 
200       for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
201          if (disp->ResourceLists[i]) {
202             _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
203             break;
204          }
205       }
206 
207       /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
208        * and invalid one is 0.
209        */
210       if (disp->Options.fd)
211          close(disp->Options.fd);
212 
213       free(disp->Options.Attribs);
214       free(disp);
215    }
216    _eglGlobal.DisplayList = NULL;
217 }
218 
219 static EGLBoolean
_eglSameAttribs(const EGLAttrib * a,const EGLAttrib * b)220 _eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b)
221 {
222    size_t na = _eglNumAttribs(a);
223    size_t nb = _eglNumAttribs(b);
224 
225    /* different numbers of attributes must be different */
226    if (na != nb)
227       return EGL_FALSE;
228 
229    /* both lists NULL are the same */
230    if (!a && !b)
231       return EGL_TRUE;
232 
233    /* otherwise, compare the lists */
234    return memcmp(a, b, na * sizeof(a[0])) == 0 ? EGL_TRUE : EGL_FALSE;
235 }
236 
237 /**
238  * Find the display corresponding to the specified native display, or create a
239  * new one. EGL 1.5 says:
240  *
241  *     Multiple calls made to eglGetPlatformDisplay with the same parameters
242  *     will return the same EGLDisplay handle.
243  *
244  * We read this extremely strictly, and treat a call with NULL attribs as
245  * different from a call with attribs only equal to { EGL_NONE }. Similarly
246  * we do not sort the attribute list, so even if all attribute _values_ are
247  * identical, different attribute orders will be considered different
248  * parameters.
249  */
250 _EGLDisplay *
_eglFindDisplay(_EGLPlatformType plat,void * plat_dpy,const EGLAttrib * attrib_list)251 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy,
252                 const EGLAttrib *attrib_list)
253 {
254    _EGLDisplay *disp;
255    size_t num_attribs;
256 
257    if (plat == _EGL_INVALID_PLATFORM)
258       return NULL;
259 
260    simple_mtx_lock(_eglGlobal.Mutex);
261 
262    /* search the display list first */
263    for (disp = _eglGlobal.DisplayList; disp; disp = disp->Next) {
264       if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy &&
265           _eglSameAttribs(disp->Options.Attribs, attrib_list))
266          goto out;
267    }
268 
269    /* create a new display */
270    assert(!disp);
271    disp = calloc(1, sizeof(_EGLDisplay));
272    if (!disp)
273       goto out;
274 
275    simple_mtx_init(&disp->Mutex, mtx_plain);
276    u_rwlock_init(&disp->TerminateLock);
277    disp->Platform = plat;
278    disp->PlatformDisplay = plat_dpy;
279    num_attribs = _eglNumAttribs(attrib_list);
280    if (num_attribs) {
281       disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib));
282       if (!disp->Options.Attribs) {
283          free(disp);
284          disp = NULL;
285          goto out;
286       }
287       memcpy(disp->Options.Attribs, attrib_list,
288              num_attribs * sizeof(EGLAttrib));
289    }
290 
291    /* add to the display list */
292    disp->Next = _eglGlobal.DisplayList;
293    _eglGlobal.DisplayList = disp;
294 
295 out:
296    simple_mtx_unlock(_eglGlobal.Mutex);
297 
298    return disp;
299 }
300 
301 /**
302  * Destroy the contexts and surfaces that are linked to the display.
303  */
304 void
_eglReleaseDisplayResources(_EGLDisplay * display)305 _eglReleaseDisplayResources(_EGLDisplay *display)
306 {
307    _EGLResource *list;
308    const _EGLDriver *drv = display->Driver;
309 
310    simple_mtx_assert_locked(&display->Mutex);
311 
312    list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
313    while (list) {
314       _EGLContext *ctx = (_EGLContext *)list;
315       list = list->Next;
316 
317       _eglUnlinkContext(ctx);
318       drv->DestroyContext(display, ctx);
319    }
320    assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
321 
322    list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
323    while (list) {
324       _EGLSurface *surf = (_EGLSurface *)list;
325       list = list->Next;
326 
327       _eglUnlinkSurface(surf);
328       drv->DestroySurface(display, surf);
329    }
330    assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
331 
332    list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
333    while (list) {
334       _EGLImage *image = (_EGLImage *)list;
335       list = list->Next;
336 
337       _eglUnlinkImage(image);
338       drv->DestroyImageKHR(display, image);
339    }
340    assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
341 
342    list = display->ResourceLists[_EGL_RESOURCE_SYNC];
343    while (list) {
344       _EGLSync *sync = (_EGLSync *)list;
345       list = list->Next;
346 
347       _eglUnlinkSync(sync);
348       drv->DestroySyncKHR(display, sync);
349    }
350    assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
351 }
352 
353 /**
354  * Free all the data hanging of an _EGLDisplay object, but not
355  * the object itself.
356  */
357 void
_eglCleanupDisplay(_EGLDisplay * disp)358 _eglCleanupDisplay(_EGLDisplay *disp)
359 {
360    if (disp->Configs) {
361       _eglDestroyArray(disp->Configs, free);
362       disp->Configs = NULL;
363    }
364 
365    /* XXX incomplete */
366 }
367 
368 /**
369  * Return EGL_TRUE if the given resource is valid.  That is, the display does
370  * own the resource.
371  */
372 EGLBoolean
_eglCheckResource(void * res,_EGLResourceType type,_EGLDisplay * disp)373 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
374 {
375    _EGLResource *list = disp->ResourceLists[type];
376 
377    simple_mtx_assert_locked(&disp->Mutex);
378 
379    if (!res)
380       return EGL_FALSE;
381 
382    while (list) {
383       if (res == (void *)list) {
384          assert(list->Display == disp);
385          break;
386       }
387       list = list->Next;
388    }
389 
390    return (list != NULL);
391 }
392 
393 /**
394  * Initialize a display resource.  The size of the subclass object is
395  * specified.
396  *
397  * This is supposed to be called from the initializers of subclasses, such as
398  * _eglInitContext or _eglInitSurface.
399  */
400 void
_eglInitResource(_EGLResource * res,EGLint size,_EGLDisplay * disp)401 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
402 {
403    memset(res, 0, size);
404    res->Display = disp;
405    res->RefCount = 1;
406 }
407 
408 /**
409  * Increment reference count for the resource.
410  */
411 void
_eglGetResource(_EGLResource * res)412 _eglGetResource(_EGLResource *res)
413 {
414    assert(res && res->RefCount > 0);
415    p_atomic_inc(&res->RefCount);
416 }
417 
418 /**
419  * Decrement reference count for the resource.
420  */
421 EGLBoolean
_eglPutResource(_EGLResource * res)422 _eglPutResource(_EGLResource *res)
423 {
424    assert(res && res->RefCount > 0);
425    return p_atomic_dec_zero(&res->RefCount);
426 }
427 
428 /**
429  * Link a resource to its display.
430  */
431 void
_eglLinkResource(_EGLResource * res,_EGLResourceType type)432 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
433 {
434    assert(res->Display);
435    simple_mtx_assert_locked(&res->Display->Mutex);
436 
437    res->IsLinked = EGL_TRUE;
438    res->Next = res->Display->ResourceLists[type];
439    res->Display->ResourceLists[type] = res;
440    _eglGetResource(res);
441 }
442 
443 /**
444  * Unlink a linked resource from its display.
445  */
446 void
_eglUnlinkResource(_EGLResource * res,_EGLResourceType type)447 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
448 {
449    _EGLResource *prev;
450 
451    simple_mtx_assert_locked(&res->Display->Mutex);
452 
453    prev = res->Display->ResourceLists[type];
454    if (prev != res) {
455       while (prev) {
456          if (prev->Next == res)
457             break;
458          prev = prev->Next;
459       }
460       assert(prev);
461       prev->Next = res->Next;
462    } else {
463       res->Display->ResourceLists[type] = res->Next;
464    }
465 
466    res->Next = NULL;
467    res->IsLinked = EGL_FALSE;
468    _eglPutResource(res);
469 
470    /* We always unlink before destroy.  The driver still owns a reference */
471    assert(res->RefCount);
472 }
473 
474 #ifdef HAVE_X11_PLATFORM
475 _EGLDisplay *
_eglGetX11Display(Display * native_display,const EGLAttrib * attrib_list)476 _eglGetX11Display(Display *native_display, const EGLAttrib *attrib_list)
477 {
478    _EGLDisplay *dpy;
479    _EGLDevice *dev = NULL;
480 
481    /* EGL_EXT_platform_x11 adds EGL_PLATFORM_X11_SCREEN_EXT,
482     * which is optional.
483     */
484    if (attrib_list != NULL) {
485       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
486          EGLAttrib attrib = attrib_list[i];
487          EGLAttrib value = attrib_list[i + 1];
488 
489          switch (attrib) {
490          case EGL_DEVICE_EXT:
491             dev = _eglLookupDevice((void *)value);
492             if (!dev) {
493                _eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
494                return NULL;
495             }
496             break;
497 
498          /* EGL_EXT_platform_x11 adds EGL_PLATFORM_X11_SCREEN_EXT,
499           * which is optional.
500           */
501          case EGL_PLATFORM_X11_SCREEN_EXT:
502             break;
503 
504          default:
505             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
506             return NULL;
507          }
508       }
509    }
510 
511    dpy = _eglFindDisplay(_EGL_PLATFORM_X11, native_display, attrib_list);
512    if (dpy) {
513       dpy->Device = dev;
514    }
515 
516    return dpy;
517 }
518 #endif /* HAVE_X11_PLATFORM */
519 
520 #ifdef HAVE_XCB_PLATFORM
521 _EGLDisplay *
_eglGetXcbDisplay(xcb_connection_t * native_display,const EGLAttrib * attrib_list)522 _eglGetXcbDisplay(xcb_connection_t *native_display,
523                   const EGLAttrib *attrib_list)
524 {
525    _EGLDisplay *dpy;
526    _EGLDevice *dev = NULL;
527 
528    /* EGL_EXT_platform_xcb recognizes exactly one attribute,
529     * EGL_PLATFORM_XCB_SCREEN_EXT, which is optional.
530     */
531    if (attrib_list != NULL) {
532       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
533          EGLAttrib attrib = attrib_list[i];
534          EGLAttrib value = attrib_list[i + 1];
535 
536          switch (attrib) {
537          case EGL_DEVICE_EXT:
538             dev = _eglLookupDevice((void *)value);
539             if (!dev) {
540                _eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
541                return NULL;
542             }
543             break;
544 
545          case EGL_PLATFORM_XCB_SCREEN_EXT:
546             break;
547 
548          default:
549             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
550             return NULL;
551          }
552       }
553    }
554 
555    dpy = _eglFindDisplay(_EGL_PLATFORM_XCB, native_display, attrib_list);
556    if (dpy) {
557       dpy->Device = dev;
558    }
559 
560    return dpy;
561 }
562 #endif /* HAVE_XCB_PLATFORM */
563 
564 #ifdef HAVE_DRM_PLATFORM
565 _EGLDisplay *
_eglGetGbmDisplay(struct gbm_device * native_display,const EGLAttrib * attrib_list)566 _eglGetGbmDisplay(struct gbm_device *native_display,
567                   const EGLAttrib *attrib_list)
568 {
569    _EGLDisplay *dpy;
570    _EGLDevice *dev = NULL;
571 
572    /* This platform recognizes only EXT_explicit_device */
573    if (attrib_list) {
574       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
575          EGLAttrib attrib = attrib_list[i];
576          EGLAttrib value = attrib_list[i + 1];
577 
578          switch (attrib) {
579          case EGL_DEVICE_EXT:
580             dev = _eglLookupDevice((void *)value);
581             if (!dev) {
582                _eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
583                return NULL;
584             }
585             break;
586 
587          default:
588             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
589             return NULL;
590          }
591       }
592    }
593 
594    dpy = _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list);
595    if (dpy) {
596       dpy->Device = dev;
597    }
598 
599    return dpy;
600 }
601 #endif /* HAVE_DRM_PLATFORM */
602 
603 #ifdef HAVE_WAYLAND_PLATFORM
604 _EGLDisplay *
_eglGetWaylandDisplay(struct wl_display * native_display,const EGLAttrib * attrib_list)605 _eglGetWaylandDisplay(struct wl_display *native_display,
606                       const EGLAttrib *attrib_list)
607 {
608    _EGLDisplay *dpy;
609    _EGLDevice *dev = NULL;
610 
611    /* This platform recognizes only EXT_explicit_device */
612    if (attrib_list) {
613       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
614          EGLAttrib attrib = attrib_list[i];
615          EGLAttrib value = attrib_list[i + 1];
616 
617          switch (attrib) {
618          case EGL_DEVICE_EXT:
619             dev = _eglLookupDevice((void *)value);
620             if (!dev) {
621                _eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
622                return NULL;
623             }
624             break;
625 
626          default:
627             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
628             return NULL;
629          }
630       }
631    }
632 
633    dpy = _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list);
634    if (dpy) {
635       dpy->Device = dev;
636    }
637 
638    return dpy;
639 }
640 #endif /* HAVE_WAYLAND_PLATFORM */
641 
642 _EGLDisplay *
_eglGetSurfacelessDisplay(void * native_display,const EGLAttrib * attrib_list)643 _eglGetSurfacelessDisplay(void *native_display, const EGLAttrib *attrib_list)
644 {
645    _EGLDisplay *dpy;
646    _EGLDevice *dev = NULL;
647 
648    /* Any native display must be an EGLDeviceEXT we know about */
649    if (native_display != NULL) {
650       _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
651       return NULL;
652    }
653 
654    /* This platform recognizes only EXT_explicit_device */
655    if (attrib_list) {
656       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
657          EGLAttrib attrib = attrib_list[i];
658          EGLAttrib value = attrib_list[i + 1];
659 
660          switch (attrib) {
661          case EGL_DEVICE_EXT:
662             dev = _eglLookupDevice((void *)value);
663             if (!dev) {
664                _eglError(EGL_BAD_DEVICE_EXT, "eglGetPlatformDisplay");
665                return NULL;
666             }
667             break;
668 
669          default:
670             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
671             return NULL;
672          }
673       }
674    }
675 
676    dpy = _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, NULL, attrib_list);
677    if (dpy) {
678       dpy->Device = dev;
679    }
680 
681    return dpy;
682 }
683 
684 #ifdef HAVE_ANDROID_PLATFORM
685 _EGLDisplay *
_eglGetAndroidDisplay(void * native_display,const EGLAttrib * attrib_list)686 _eglGetAndroidDisplay(void *native_display, const EGLAttrib *attrib_list)
687 {
688 
689    /* This platform recognizes no display attributes. */
690    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
691       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
692       return NULL;
693    }
694 
695    return _eglFindDisplay(_EGL_PLATFORM_ANDROID, native_display, attrib_list);
696 }
697 #endif /* HAVE_ANDROID_PLATFORM */
698 
699 _EGLDisplay *
_eglGetDeviceDisplay(void * native_display,const EGLAttrib * attrib_list)700 _eglGetDeviceDisplay(void *native_display, const EGLAttrib *attrib_list)
701 {
702    _EGLDevice *dev;
703    _EGLDisplay *display;
704    int fd = -1;
705 
706    dev = _eglLookupDevice(native_display);
707    if (!dev) {
708       _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
709       return NULL;
710    }
711 
712    if (attrib_list) {
713       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
714          EGLAttrib attrib = attrib_list[i];
715          EGLAttrib value = attrib_list[i + 1];
716 
717          /* EGL_EXT_platform_device does not recognize any attributes,
718           * EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
719           */
720 
721          if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
722              attrib != EGL_DRM_MASTER_FD_EXT) {
723             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
724             return NULL;
725          }
726 
727          fd = (int)value;
728       }
729    }
730 
731    display = _eglFindDisplay(_EGL_PLATFORM_DEVICE, native_display, attrib_list);
732    if (!display) {
733       _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
734       return NULL;
735    }
736 
737    /* If the fd is explicitly provided and we did not dup() it yet, do so.
738     * The spec mandates that we do so, since we'll need it past the
739     * eglGetPlatformDisplay call.
740     *
741     * The new fd is guaranteed to be 3 or greater.
742     */
743    if (fd != -1 && display->Options.fd == 0) {
744       display->Options.fd = os_dupfd_cloexec(fd);
745       if (display->Options.fd == -1) {
746          /* Do not (really) need to teardown the display */
747          _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
748          return NULL;
749       }
750    }
751 
752    return display;
753 }
754