1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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 "eglcontext.h"
39 #include "eglsurface.h"
40 #include "egldisplay.h"
41 #include "egldriver.h"
42 #include "eglglobals.h"
46 /* Includes for _eglNativePlatformDetectNativeDisplay */
51 #ifdef HAVE_WAYLAND_PLATFORM
52 #include <wayland-client.h>
54 #ifdef HAVE_DRM_PLATFORM
57 #ifdef HAVE_FBDEV_PLATFORM
59 #include <sys/types.h>
65 * Map --with-egl-platforms names to platform types.
68 _EGLPlatformType platform;
70 } egl_platforms[_EGL_NUM_PLATFORMS] = {
71 { _EGL_PLATFORM_WINDOWS, "gdi" },
72 { _EGL_PLATFORM_X11, "x11" },
73 { _EGL_PLATFORM_WAYLAND, "wayland" },
74 { _EGL_PLATFORM_DRM, "drm" },
75 { _EGL_PLATFORM_FBDEV, "fbdev" },
76 { _EGL_PLATFORM_NULL, "null" },
77 { _EGL_PLATFORM_ANDROID, "android" }
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 plat_name = getenv("EGL_PLATFORM");
92 /* try deprecated env variable */
93 if (!plat_name || !plat_name[0])
94 plat_name = getenv("EGL_DISPLAY");
95 if (!plat_name || !plat_name[0])
96 return _EGL_INVALID_PLATFORM;
98 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
99 if (strcmp(egl_platforms[i].name, plat_name) == 0) {
100 plat = egl_platforms[i].platform;
110 * Perform validity checks on a generic pointer.
113 _eglPointerIsDereferencable(void *p)
116 uintptr_t addr = (uintptr_t) p;
117 unsigned char valid = 0;
118 const long page_size = getpagesize();
123 /* align addr to page_size */
124 addr &= ~(page_size - 1);
126 if (mincore((void *) addr, page_size, &valid) < 0) {
127 _eglLog(_EGL_DEBUG, "mincore failed: %m");
131 return (valid & 0x01) == 0x01;
139 * Try detecting native platform with the help of native display characteristcs.
141 static _EGLPlatformType
142 _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay)
144 #ifdef HAVE_FBDEV_PLATFORM
148 if (nativeDisplay == EGL_DEFAULT_DISPLAY)
149 return _EGL_INVALID_PLATFORM;
151 #ifdef HAVE_FBDEV_PLATFORM
152 /* fbdev is the only platform that can be a file descriptor. */
153 if (fstat((intptr_t) nativeDisplay, &buf) == 0 && S_ISCHR(buf.st_mode))
154 return _EGL_PLATFORM_FBDEV;
157 if (_eglPointerIsDereferencable(nativeDisplay)) {
158 void *first_pointer = *(void **) nativeDisplay;
160 (void) first_pointer; /* silence unused var warning */
162 #ifdef HAVE_WAYLAND_PLATFORM
163 /* wl_display is a wl_proxy, which is a wl_object.
164 * wl_object's first element points to the interfacetype. */
165 if (first_pointer == &wl_display_interface)
166 return _EGL_PLATFORM_WAYLAND;
169 #ifdef HAVE_DRM_PLATFORM
170 /* gbm has a pointer to its constructor as first element. */
171 if (first_pointer == gbm_create_device)
172 return _EGL_PLATFORM_DRM;
175 #ifdef HAVE_X11_PLATFORM
176 /* If not matched to any other platform, fallback to x11. */
177 return _EGL_PLATFORM_X11;
181 return _EGL_INVALID_PLATFORM;
186 * Return the native platform. It is the platform of the EGL native types.
189 _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay)
191 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
192 char *detection_method = NULL;
194 if (native_platform == _EGL_INVALID_PLATFORM) {
195 native_platform = _eglGetNativePlatformFromEnv();
196 detection_method = "environment overwrite";
197 if (native_platform == _EGL_INVALID_PLATFORM) {
198 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
199 detection_method = "autodetected";
200 if (native_platform == _EGL_INVALID_PLATFORM) {
201 native_platform = _EGL_NATIVE_PLATFORM;
202 detection_method = "build-time configuration";
207 if (detection_method != NULL)
208 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
209 egl_platforms[native_platform].name, detection_method);
211 return native_platform;
216 * Finish display management.
219 _eglFiniDisplay(void)
221 _EGLDisplay *dpyList, *dpy;
223 /* atexit function is called with global mutex locked */
224 dpyList = _eglGlobal.DisplayList;
230 dpyList = dpyList->Next;
232 for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
233 if (dpy->ResourceLists[i]) {
234 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
241 _eglGlobal.DisplayList = NULL;
246 * Find the display corresponding to the specified native display, or create a
250 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
254 if (plat == _EGL_INVALID_PLATFORM)
257 _eglLockMutex(_eglGlobal.Mutex);
259 /* search the display list first */
260 dpy = _eglGlobal.DisplayList;
262 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
267 /* create a new display */
269 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
271 _eglInitMutex(&dpy->Mutex);
272 dpy->Platform = plat;
273 dpy->PlatformDisplay = plat_dpy;
275 /* add to the display list */
276 dpy->Next = _eglGlobal.DisplayList;
277 _eglGlobal.DisplayList = dpy;
281 _eglUnlockMutex(_eglGlobal.Mutex);
288 * Destroy the contexts and surfaces that are linked to the display.
291 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
295 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
297 _EGLContext *ctx = (_EGLContext *) list;
300 _eglUnlinkContext(ctx);
301 drv->API.DestroyContext(drv, display, ctx);
303 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
305 list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
307 _EGLSurface *surf = (_EGLSurface *) list;
310 _eglUnlinkSurface(surf);
311 drv->API.DestroySurface(drv, display, surf);
313 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
318 * Free all the data hanging of an _EGLDisplay object, but not
322 _eglCleanupDisplay(_EGLDisplay *disp)
325 _eglDestroyArray(disp->Configs, free);
326 disp->Configs = NULL;
334 * Return EGL_TRUE if the given handle is a valid handle to a display.
337 _eglCheckDisplayHandle(EGLDisplay dpy)
341 _eglLockMutex(_eglGlobal.Mutex);
342 cur = _eglGlobal.DisplayList;
344 if (cur == (_EGLDisplay *) dpy)
348 _eglUnlockMutex(_eglGlobal.Mutex);
349 return (cur != NULL);
354 * Return EGL_TRUE if the given resource is valid. That is, the display does
358 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
360 _EGLResource *list = dpy->ResourceLists[type];
366 if (res == (void *) list) {
367 assert(list->Display == dpy);
373 return (list != NULL);
378 * Initialize a display resource.
381 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
383 memset(res, 0, size);
390 * Increment reference count for the resource.
393 _eglGetResource(_EGLResource *res)
395 assert(res && res->RefCount > 0);
396 /* hopefully a resource is always manipulated with its display locked */
402 * Decrement reference count for the resource.
405 _eglPutResource(_EGLResource *res)
407 assert(res && res->RefCount > 0);
409 return (!res->RefCount);
414 * Link a resource to its display.
417 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
419 assert(res->Display);
421 res->IsLinked = EGL_TRUE;
422 res->Next = res->Display->ResourceLists[type];
423 res->Display->ResourceLists[type] = res;
424 _eglGetResource(res);
429 * Unlink a linked resource from its display.
432 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
436 prev = res->Display->ResourceLists[type];
439 if (prev->Next == res)
444 prev->Next = res->Next;
447 res->Display->ResourceLists[type] = res->Next;
451 res->IsLinked = EGL_FALSE;
452 _eglPutResource(res);
454 /* We always unlink before destroy. The driver still owns a reference */
455 assert(res->RefCount);