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