1 /**************************************************************************
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
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:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
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.
28 **************************************************************************/
32 * Functions related to EGLDisplay.
40 #include "c11/threads.h"
41 #include "util/macros.h"
42 #include "util/u_atomic.h"
44 #include "eglcontext.h"
45 #include "eglcurrent.h"
46 #include "eglsurface.h"
47 #include "egldevice.h"
48 #include "egldisplay.h"
49 #include "egldriver.h"
50 #include "eglglobals.h"
55 /* Includes for _eglNativePlatformDetectNativeDisplay */
56 #ifdef HAVE_WAYLAND_PLATFORM
57 #include <wayland-client.h>
59 #ifdef HAVE_DRM_PLATFORM
65 * Map build-system platform names to platform types.
68 _EGLPlatformType platform
;
71 { _EGL_PLATFORM_X11
, "x11" },
72 { _EGL_PLATFORM_WAYLAND
, "wayland" },
73 { _EGL_PLATFORM_DRM
, "drm" },
74 { _EGL_PLATFORM_ANDROID
, "android" },
75 { _EGL_PLATFORM_HAIKU
, "haiku" },
76 { _EGL_PLATFORM_SURFACELESS
, "surfaceless" },
77 { _EGL_PLATFORM_DEVICE
, "device" },
82 * Return the native platform by parsing EGL_PLATFORM.
84 static _EGLPlatformType
85 _eglGetNativePlatformFromEnv(void)
87 _EGLPlatformType plat
= _EGL_INVALID_PLATFORM
;
88 const char *plat_name
;
91 static_assert(ARRAY_SIZE(egl_platforms
) == _EGL_NUM_PLATFORMS
,
94 plat_name
= getenv("EGL_PLATFORM");
95 /* try deprecated env variable */
96 if (!plat_name
|| !plat_name
[0])
97 plat_name
= getenv("EGL_DISPLAY");
98 if (!plat_name
|| !plat_name
[0])
99 return _EGL_INVALID_PLATFORM
;
101 for (i
= 0; i
< ARRAY_SIZE(egl_platforms
); i
++) {
102 if (strcmp(egl_platforms
[i
].name
, plat_name
) == 0) {
103 plat
= egl_platforms
[i
].platform
;
108 if (plat
== _EGL_INVALID_PLATFORM
)
109 _eglLog(_EGL_WARNING
, "invalid EGL_PLATFORM given");
116 * Try detecting native platform with the help of native display characteristcs.
118 static _EGLPlatformType
119 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay
)
121 if (nativeDisplay
== EGL_DEFAULT_DISPLAY
)
122 return _EGL_INVALID_PLATFORM
;
124 if (_eglPointerIsDereferencable(nativeDisplay
)) {
125 void *first_pointer
= *(void **) nativeDisplay
;
127 (void) first_pointer
; /* silence unused var warning */
129 #ifdef HAVE_WAYLAND_PLATFORM
130 /* wl_display is a wl_proxy, which is a wl_object.
131 * wl_object's first element points to the interfacetype. */
132 if (first_pointer
== &wl_display_interface
)
133 return _EGL_PLATFORM_WAYLAND
;
136 #ifdef HAVE_DRM_PLATFORM
137 /* gbm has a pointer to its constructor as first element. */
138 if (first_pointer
== gbm_create_device
)
139 return _EGL_PLATFORM_DRM
;
142 #ifdef HAVE_X11_PLATFORM
143 /* If not matched to any other platform, fallback to x11. */
144 return _EGL_PLATFORM_X11
;
147 #ifdef HAVE_HAIKU_PLATFORM
148 return _EGL_PLATFORM_HAIKU
;
152 return _EGL_INVALID_PLATFORM
;
157 * Return the native platform. It is the platform of the EGL native types.
160 _eglGetNativePlatform(void *nativeDisplay
)
162 static _EGLPlatformType native_platform
= _EGL_INVALID_PLATFORM
;
163 _EGLPlatformType detected_platform
= native_platform
;
165 if (detected_platform
== _EGL_INVALID_PLATFORM
) {
166 const char *detection_method
;
168 detected_platform
= _eglGetNativePlatformFromEnv();
169 detection_method
= "environment overwrite";
171 if (detected_platform
== _EGL_INVALID_PLATFORM
) {
172 detected_platform
= _eglNativePlatformDetectNativeDisplay(nativeDisplay
);
173 detection_method
= "autodetected";
176 if (detected_platform
== _EGL_INVALID_PLATFORM
) {
177 detected_platform
= _EGL_NATIVE_PLATFORM
;
178 detection_method
= "build-time configuration";
181 _eglLog(_EGL_DEBUG
, "Native platform type: %s (%s)",
182 egl_platforms
[detected_platform
].name
, detection_method
);
184 p_atomic_cmpxchg(&native_platform
, _EGL_INVALID_PLATFORM
,
188 return native_platform
;
193 * Finish display management.
196 _eglFiniDisplay(void)
198 _EGLDisplay
*dispList
, *disp
;
200 /* atexit function is called with global mutex locked */
201 dispList
= _eglGlobal
.DisplayList
;
207 dispList
= dispList
->Next
;
209 for (i
= 0; i
< _EGL_NUM_RESOURCES
; i
++) {
210 if (disp
->ResourceLists
[i
]) {
211 _eglLog(_EGL_DEBUG
, "Display %p is destroyed with resources", disp
);
217 /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
218 * and invalid one is 0.
220 if (disp
->Options
.fd
)
221 close(disp
->Options
.fd
);
223 free(disp
->Options
.Attribs
);
226 _eglGlobal
.DisplayList
= NULL
;
230 _eglSameAttribs(const EGLAttrib
*a
, const EGLAttrib
*b
)
232 size_t na
= _eglNumAttribs(a
);
233 size_t nb
= _eglNumAttribs(b
);
235 /* different numbers of attributes must be different */
239 /* both lists NULL are the same */
243 /* otherwise, compare the lists */
244 return memcmp(a
, b
, na
* sizeof(a
[0])) == 0 ? EGL_TRUE
: EGL_FALSE
;
248 * Find the display corresponding to the specified native display, or create a
249 * new one. EGL 1.5 says:
251 * Multiple calls made to eglGetPlatformDisplay with the same parameters
252 * will return the same EGLDisplay handle.
254 * We read this extremely strictly, and treat a call with NULL attribs as
255 * different from a call with attribs only equal to { EGL_NONE }. Similarly
256 * we do not sort the attribute list, so even if all attribute _values_ are
257 * identical, different attribute orders will be considered different
261 _eglFindDisplay(_EGLPlatformType plat
, void *plat_dpy
,
262 const EGLAttrib
*attrib_list
)
267 if (plat
== _EGL_INVALID_PLATFORM
)
270 mtx_lock(_eglGlobal
.Mutex
);
272 /* search the display list first */
273 for (disp
= _eglGlobal
.DisplayList
; disp
; disp
= disp
->Next
) {
274 if (disp
->Platform
== plat
&& disp
->PlatformDisplay
== plat_dpy
&&
275 _eglSameAttribs(disp
->Options
.Attribs
, attrib_list
))
279 /* create a new display */
281 disp
= calloc(1, sizeof(_EGLDisplay
));
283 mtx_init(&disp
->Mutex
, mtx_plain
);
284 disp
->Platform
= plat
;
285 disp
->PlatformDisplay
= plat_dpy
;
286 num_attribs
= _eglNumAttribs(attrib_list
);
288 disp
->Options
.Attribs
= calloc(num_attribs
, sizeof(EGLAttrib
));
289 if (!disp
->Options
.Attribs
) {
294 memcpy(disp
->Options
.Attribs
, attrib_list
,
295 num_attribs
* sizeof(EGLAttrib
));
297 /* add to the display list */
298 disp
->Next
= _eglGlobal
.DisplayList
;
299 _eglGlobal
.DisplayList
= disp
;
304 mtx_unlock(_eglGlobal
.Mutex
);
311 * Destroy the contexts and surfaces that are linked to the display.
314 _eglReleaseDisplayResources(_EGLDriver
*drv
, _EGLDisplay
*display
)
318 list
= display
->ResourceLists
[_EGL_RESOURCE_CONTEXT
];
320 _EGLContext
*ctx
= (_EGLContext
*) list
;
323 _eglUnlinkContext(ctx
);
324 drv
->API
.DestroyContext(drv
, display
, ctx
);
326 assert(!display
->ResourceLists
[_EGL_RESOURCE_CONTEXT
]);
328 list
= display
->ResourceLists
[_EGL_RESOURCE_SURFACE
];
330 _EGLSurface
*surf
= (_EGLSurface
*) list
;
333 _eglUnlinkSurface(surf
);
334 drv
->API
.DestroySurface(drv
, display
, surf
);
336 assert(!display
->ResourceLists
[_EGL_RESOURCE_SURFACE
]);
338 list
= display
->ResourceLists
[_EGL_RESOURCE_IMAGE
];
340 _EGLImage
*image
= (_EGLImage
*) list
;
343 _eglUnlinkImage(image
);
344 drv
->API
.DestroyImageKHR(drv
, display
, image
);
346 assert(!display
->ResourceLists
[_EGL_RESOURCE_IMAGE
]);
348 list
= display
->ResourceLists
[_EGL_RESOURCE_SYNC
];
350 _EGLSync
*sync
= (_EGLSync
*) list
;
353 _eglUnlinkSync(sync
);
354 drv
->API
.DestroySyncKHR(drv
, display
, sync
);
356 assert(!display
->ResourceLists
[_EGL_RESOURCE_SYNC
]);
361 * Free all the data hanging of an _EGLDisplay object, but not
365 _eglCleanupDisplay(_EGLDisplay
*disp
)
368 _eglDestroyArray(disp
->Configs
, free
);
369 disp
->Configs
= NULL
;
377 * Return EGL_TRUE if the given handle is a valid handle to a display.
380 _eglCheckDisplayHandle(EGLDisplay dpy
)
384 mtx_lock(_eglGlobal
.Mutex
);
385 cur
= _eglGlobal
.DisplayList
;
387 if (cur
== (_EGLDisplay
*) dpy
)
391 mtx_unlock(_eglGlobal
.Mutex
);
392 return (cur
!= NULL
);
397 * Return EGL_TRUE if the given resource is valid. That is, the display does
401 _eglCheckResource(void *res
, _EGLResourceType type
, _EGLDisplay
*disp
)
403 _EGLResource
*list
= disp
->ResourceLists
[type
];
409 if (res
== (void *) list
) {
410 assert(list
->Display
== disp
);
416 return (list
!= NULL
);
421 * Initialize a display resource. The size of the subclass object is
424 * This is supposed to be called from the initializers of subclasses, such as
425 * _eglInitContext or _eglInitSurface.
428 _eglInitResource(_EGLResource
*res
, EGLint size
, _EGLDisplay
*disp
)
430 memset(res
, 0, size
);
437 * Increment reference count for the resource.
440 _eglGetResource(_EGLResource
*res
)
442 assert(res
&& res
->RefCount
> 0);
443 /* hopefully a resource is always manipulated with its display locked */
449 * Decrement reference count for the resource.
452 _eglPutResource(_EGLResource
*res
)
454 assert(res
&& res
->RefCount
> 0);
456 return (!res
->RefCount
);
461 * Link a resource to its display.
464 _eglLinkResource(_EGLResource
*res
, _EGLResourceType type
)
466 assert(res
->Display
);
468 res
->IsLinked
= EGL_TRUE
;
469 res
->Next
= res
->Display
->ResourceLists
[type
];
470 res
->Display
->ResourceLists
[type
] = res
;
471 _eglGetResource(res
);
476 * Unlink a linked resource from its display.
479 _eglUnlinkResource(_EGLResource
*res
, _EGLResourceType type
)
483 prev
= res
->Display
->ResourceLists
[type
];
486 if (prev
->Next
== res
)
491 prev
->Next
= res
->Next
;
494 res
->Display
->ResourceLists
[type
] = res
->Next
;
498 res
->IsLinked
= EGL_FALSE
;
499 _eglPutResource(res
);
501 /* We always unlink before destroy. The driver still owns a reference */
502 assert(res
->RefCount
);
505 #ifdef HAVE_X11_PLATFORM
507 _eglGetX11Display(Display
*native_display
,
508 const EGLAttrib
*attrib_list
)
510 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
511 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
513 if (attrib_list
!= NULL
) {
514 for (int i
= 0; attrib_list
[i
] != EGL_NONE
; i
+= 2) {
515 if (attrib_list
[i
] != EGL_PLATFORM_X11_SCREEN_EXT
) {
516 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
521 return _eglFindDisplay(_EGL_PLATFORM_X11
, native_display
, attrib_list
);
523 #endif /* HAVE_X11_PLATFORM */
525 #ifdef HAVE_DRM_PLATFORM
527 _eglGetGbmDisplay(struct gbm_device
*native_display
,
528 const EGLAttrib
*attrib_list
)
530 /* EGL_MESA_platform_gbm recognizes no attributes. */
531 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
532 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
536 return _eglFindDisplay(_EGL_PLATFORM_DRM
, native_display
, attrib_list
);
538 #endif /* HAVE_DRM_PLATFORM */
540 #ifdef HAVE_WAYLAND_PLATFORM
542 _eglGetWaylandDisplay(struct wl_display
*native_display
,
543 const EGLAttrib
*attrib_list
)
545 /* EGL_EXT_platform_wayland recognizes no attributes. */
546 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
547 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
551 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND
, native_display
, attrib_list
);
553 #endif /* HAVE_WAYLAND_PLATFORM */
555 #ifdef HAVE_SURFACELESS_PLATFORM
557 _eglGetSurfacelessDisplay(void *native_display
,
558 const EGLAttrib
*attrib_list
)
560 /* This platform has no native display. */
561 if (native_display
!= NULL
) {
562 _eglError(EGL_BAD_PARAMETER
, "eglGetPlatformDisplay");
566 /* This platform recognizes no display attributes. */
567 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
568 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
572 return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS
, native_display
,
575 #endif /* HAVE_SURFACELESS_PLATFORM */
577 #ifdef HAVE_ANDROID_PLATFORM
579 _eglGetAndroidDisplay(void *native_display
,
580 const EGLAttrib
*attrib_list
)
583 /* This platform recognizes no display attributes. */
584 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
585 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
589 return _eglFindDisplay(_EGL_PLATFORM_ANDROID
, native_display
,
592 #endif /* HAVE_ANDROID_PLATFORM */
595 _eglGetDeviceDisplay(void *native_display
,
596 const EGLAttrib
*attrib_list
)
599 _EGLDisplay
*display
;
602 dev
= _eglLookupDevice(native_display
);
604 _eglError(EGL_BAD_PARAMETER
, "eglGetPlatformDisplay");
609 for (int i
= 0; attrib_list
[i
] != EGL_NONE
; i
+= 2) {
610 EGLAttrib attrib
= attrib_list
[i
];
611 EGLAttrib value
= attrib_list
[i
+ 1];
613 /* EGL_EXT_platform_device does not recognize any attributes,
614 * EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
617 if (!_eglDeviceSupports(dev
, _EGL_DEVICE_DRM
) ||
618 attrib
!= EGL_DRM_MASTER_FD_EXT
) {
619 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
627 display
= _eglFindDisplay(_EGL_PLATFORM_DEVICE
, native_display
, attrib_list
);
629 _eglError(EGL_BAD_ALLOC
, "eglGetPlatformDisplay");
633 /* If the fd is explicitly provided and we did not dup() it yet, do so.
634 * The spec mandates that we do so, since we'll need it past the
635 * eglGetPlatformDispay call.
637 * The new fd is guaranteed to be 3 or greater.
639 if (fd
!= -1 && display
->Options
.fd
== 0) {
640 display
->Options
.fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
641 if (display
->Options
.fd
== -1) {
642 /* Do not (really) need to teardown the display */
643 _eglError(EGL_BAD_ALLOC
, "eglGetPlatformDisplay");