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