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.
38 #include "c11/threads.h"
40 #include "eglcontext.h"
41 #include "eglcurrent.h"
42 #include "eglsurface.h"
43 #include "egldisplay.h"
44 #include "egldriver.h"
45 #include "eglglobals.h"
48 /* Includes for _eglNativePlatformDetectNativeDisplay */
53 #ifdef HAVE_WAYLAND_PLATFORM
54 #include <wayland-client.h>
56 #ifdef HAVE_DRM_PLATFORM
62 * Map --with-egl-platforms names to platform types.
65 _EGLPlatformType platform
;
67 } egl_platforms
[_EGL_NUM_PLATFORMS
] = {
68 { _EGL_PLATFORM_X11
, "x11" },
69 { _EGL_PLATFORM_WAYLAND
, "wayland" },
70 { _EGL_PLATFORM_DRM
, "drm" },
71 { _EGL_PLATFORM_ANDROID
, "android" },
72 { _EGL_PLATFORM_HAIKU
, "haiku" },
73 { _EGL_PLATFORM_SURFACELESS
, "surfaceless" },
78 * Return the native platform by parsing EGL_PLATFORM.
80 static _EGLPlatformType
81 _eglGetNativePlatformFromEnv(void)
83 _EGLPlatformType plat
= _EGL_INVALID_PLATFORM
;
84 const char *plat_name
;
87 plat_name
= getenv("EGL_PLATFORM");
88 /* try deprecated env variable */
89 if (!plat_name
|| !plat_name
[0])
90 plat_name
= getenv("EGL_DISPLAY");
91 if (!plat_name
|| !plat_name
[0])
92 return _EGL_INVALID_PLATFORM
;
94 for (i
= 0; i
< _EGL_NUM_PLATFORMS
; i
++) {
95 if (strcmp(egl_platforms
[i
].name
, plat_name
) == 0) {
96 plat
= egl_platforms
[i
].platform
;
106 * Perform validity checks on a generic pointer.
109 _eglPointerIsDereferencable(void *p
)
112 uintptr_t addr
= (uintptr_t) p
;
113 unsigned char valid
= 0;
114 const long page_size
= getpagesize();
119 /* align addr to page_size */
120 addr
&= ~(page_size
- 1);
122 if (mincore((void *) addr
, page_size
, &valid
) < 0) {
123 _eglLog(_EGL_DEBUG
, "mincore failed: %m");
127 return (valid
& 0x01) == 0x01;
135 * Try detecting native platform with the help of native display characteristcs.
137 static _EGLPlatformType
138 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay
)
140 if (nativeDisplay
== EGL_DEFAULT_DISPLAY
)
141 return _EGL_INVALID_PLATFORM
;
143 if (_eglPointerIsDereferencable(nativeDisplay
)) {
144 void *first_pointer
= *(void **) nativeDisplay
;
146 (void) first_pointer
; /* silence unused var warning */
148 #ifdef HAVE_WAYLAND_PLATFORM
149 /* wl_display is a wl_proxy, which is a wl_object.
150 * wl_object's first element points to the interfacetype. */
151 if (first_pointer
== &wl_display_interface
)
152 return _EGL_PLATFORM_WAYLAND
;
155 #ifdef HAVE_DRM_PLATFORM
156 /* gbm has a pointer to its constructor as first element. */
157 if (first_pointer
== gbm_create_device
)
158 return _EGL_PLATFORM_DRM
;
161 #ifdef HAVE_X11_PLATFORM
162 /* If not matched to any other platform, fallback to x11. */
163 return _EGL_PLATFORM_X11
;
166 #ifdef HAVE_HAIKU_PLATFORM
167 return _EGL_PLATFORM_HAIKU
;
171 return _EGL_INVALID_PLATFORM
;
176 * Return the native platform. It is the platform of the EGL native types.
179 _eglGetNativePlatform(void *nativeDisplay
)
181 static _EGLPlatformType native_platform
= _EGL_INVALID_PLATFORM
;
182 char *detection_method
= NULL
;
184 if (native_platform
== _EGL_INVALID_PLATFORM
) {
185 native_platform
= _eglGetNativePlatformFromEnv();
186 detection_method
= "environment overwrite";
187 if (native_platform
== _EGL_INVALID_PLATFORM
) {
188 native_platform
= _eglNativePlatformDetectNativeDisplay(nativeDisplay
);
189 detection_method
= "autodetected";
190 if (native_platform
== _EGL_INVALID_PLATFORM
) {
191 native_platform
= _EGL_NATIVE_PLATFORM
;
192 detection_method
= "build-time configuration";
197 if (detection_method
!= NULL
)
198 _eglLog(_EGL_DEBUG
, "Native platform type: %s (%s)",
199 egl_platforms
[native_platform
].name
, detection_method
);
201 return native_platform
;
206 * Finish display management.
209 _eglFiniDisplay(void)
211 _EGLDisplay
*dpyList
, *dpy
;
213 /* atexit function is called with global mutex locked */
214 dpyList
= _eglGlobal
.DisplayList
;
220 dpyList
= dpyList
->Next
;
222 for (i
= 0; i
< _EGL_NUM_RESOURCES
; i
++) {
223 if (dpy
->ResourceLists
[i
]) {
224 _eglLog(_EGL_DEBUG
, "Display %p is destroyed with resources", dpy
);
231 _eglGlobal
.DisplayList
= NULL
;
236 * Find the display corresponding to the specified native display, or create a
240 _eglFindDisplay(_EGLPlatformType plat
, void *plat_dpy
)
243 _EGLThreadInfo
*thread
= _eglGetCurrentThread();
245 if (plat
== _EGL_INVALID_PLATFORM
)
248 mtx_lock(_eglGlobal
.Mutex
);
250 /* search the display list first */
251 dpy
= _eglGlobal
.DisplayList
;
253 if (dpy
->Platform
== plat
&& dpy
->PlatformDisplay
== plat_dpy
)
258 /* create a new display */
260 dpy
= calloc(1, sizeof(_EGLDisplay
));
262 mtx_init(&dpy
->Mutex
, mtx_plain
);
263 dpy
->Platform
= plat
;
264 dpy
->PlatformDisplay
= plat_dpy
;
266 /* add to the display list */
267 dpy
->Next
= _eglGlobal
.DisplayList
;
268 _eglGlobal
.DisplayList
= dpy
;
269 dpy
->ThreadList
= NULL
;
273 thread
->Next
= dpy
->ThreadList
;
274 dpy
->ThreadList
= thread
;
276 mtx_unlock(_eglGlobal
.Mutex
);
283 * Destroy the contexts and surfaces that are linked to the display.
286 _eglReleaseDisplayResources(_EGLDriver
*drv
, _EGLDisplay
*display
)
290 list
= display
->ResourceLists
[_EGL_RESOURCE_CONTEXT
];
292 _EGLContext
*ctx
= (_EGLContext
*) list
;
295 _eglUnlinkContext(ctx
);
296 drv
->API
.DestroyContext(drv
, display
, ctx
);
298 assert(!display
->ResourceLists
[_EGL_RESOURCE_CONTEXT
]);
300 list
= display
->ResourceLists
[_EGL_RESOURCE_SURFACE
];
302 _EGLSurface
*surf
= (_EGLSurface
*) list
;
305 _eglUnlinkSurface(surf
);
306 drv
->API
.DestroySurface(drv
, display
, surf
);
308 assert(!display
->ResourceLists
[_EGL_RESOURCE_SURFACE
]);
313 * Free all the data hanging of an _EGLDisplay object, but not
317 _eglCleanupDisplay(_EGLDisplay
*disp
)
320 _eglDestroyArray(disp
->Configs
, free
);
321 disp
->Configs
= NULL
;
329 * Return EGL_TRUE if the given handle is a valid handle to a display.
332 _eglCheckDisplayHandle(EGLDisplay dpy
)
336 mtx_lock(_eglGlobal
.Mutex
);
337 cur
= _eglGlobal
.DisplayList
;
339 if (cur
== (_EGLDisplay
*) dpy
)
343 mtx_unlock(_eglGlobal
.Mutex
);
344 return (cur
!= NULL
);
349 * Return EGL_TRUE if the given resource is valid. That is, the display does
353 _eglCheckResource(void *res
, _EGLResourceType type
, _EGLDisplay
*dpy
)
355 _EGLResource
*list
= dpy
->ResourceLists
[type
];
361 if (res
== (void *) list
) {
362 assert(list
->Display
== dpy
);
368 return (list
!= NULL
);
373 * Initialize a display resource. The size of the subclass object is
376 * This is supposed to be called from the initializers of subclasses, such as
377 * _eglInitContext or _eglInitSurface.
380 _eglInitResource(_EGLResource
*res
, EGLint size
, _EGLDisplay
*dpy
)
382 memset(res
, 0, size
);
389 * Increment reference count for the resource.
392 _eglGetResource(_EGLResource
*res
)
394 assert(res
&& res
->RefCount
> 0);
395 /* hopefully a resource is always manipulated with its display locked */
401 * Decrement reference count for the resource.
404 _eglPutResource(_EGLResource
*res
)
406 assert(res
&& res
->RefCount
> 0);
408 return (!res
->RefCount
);
413 * Link a resource to its display.
416 _eglLinkResource(_EGLResource
*res
, _EGLResourceType type
)
418 assert(res
->Display
);
420 res
->IsLinked
= EGL_TRUE
;
421 res
->Next
= res
->Display
->ResourceLists
[type
];
422 res
->Display
->ResourceLists
[type
] = res
;
423 _eglGetResource(res
);
428 * Unlink a linked resource from its display.
431 _eglUnlinkResource(_EGLResource
*res
, _EGLResourceType type
)
435 prev
= res
->Display
->ResourceLists
[type
];
438 if (prev
->Next
== res
)
443 prev
->Next
= res
->Next
;
446 res
->Display
->ResourceLists
[type
] = res
->Next
;
450 res
->IsLinked
= EGL_FALSE
;
451 _eglPutResource(res
);
453 /* We always unlink before destroy. The driver still owns a reference */
454 assert(res
->RefCount
);
457 #ifdef HAVE_X11_PLATFORM
459 _eglParseX11DisplayAttribList(const EGLint
*attrib_list
)
463 if (attrib_list
== NULL
) {
467 for (i
= 0; attrib_list
[i
] != EGL_NONE
; i
+= 2) {
468 EGLint attrib
= attrib_list
[i
];
469 EGLint value
= attrib_list
[i
+ 1];
471 /* EGL_EXT_platform_x11 recognizes exactly one attribute,
472 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
474 * Mesa supports connecting to only the default screen, so we reject
477 if (attrib
!= EGL_PLATFORM_X11_SCREEN_EXT
|| value
!= 0) {
478 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
487 _eglGetX11Display(Display
*native_display
,
488 const EGLint
*attrib_list
)
490 if (!_eglParseX11DisplayAttribList(attrib_list
)) {
494 return _eglFindDisplay(_EGL_PLATFORM_X11
, native_display
);
496 #endif /* HAVE_X11_PLATFORM */
498 #ifdef HAVE_DRM_PLATFORM
500 _eglGetGbmDisplay(struct gbm_device
*native_display
,
501 const EGLint
*attrib_list
)
503 /* EGL_MESA_platform_gbm recognizes no attributes. */
504 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
505 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
509 return _eglFindDisplay(_EGL_PLATFORM_DRM
, native_display
);
511 #endif /* HAVE_DRM_PLATFORM */
513 #ifdef HAVE_WAYLAND_PLATFORM
515 _eglGetWaylandDisplay(struct wl_display
*native_display
,
516 const EGLint
*attrib_list
)
518 /* EGL_EXT_platform_wayland recognizes no attributes. */
519 if (attrib_list
!= NULL
&& attrib_list
[0] != EGL_NONE
) {
520 _eglError(EGL_BAD_ATTRIBUTE
, "eglGetPlatformDisplay");
524 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND
, native_display
);
526 #endif /* HAVE_WAYLAND_PLATFORM */