1 /************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe (at) 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 #include "eglcontext.h" 39 #include "eglsurface.h" 40 #include "egldisplay.h" 41 #include "egldriver.h" 42 #include "eglglobals.h" 43 #include "eglmutex.h" 44 #include "egllog.h" 45 46 /* Includes for _eglNativePlatformDetectNativeDisplay */ 47 #ifdef HAVE_MINCORE 48 #include <unistd.h> 49 #include <sys/mman.h> 50 #endif 51 #ifdef HAVE_WAYLAND_PLATFORM 52 #include <wayland-client.h> 53 #endif 54 #ifdef HAVE_DRM_PLATFORM 55 #include <gbm.h> 56 #endif 57 #ifdef HAVE_FBDEV_PLATFORM 58 #include <stdint.h> 59 #include <sys/types.h> 60 #include <sys/stat.h> 61 #endif 62 63 64 /** 65 * Map --with-egl-platforms names to platform types. 66 */ 67 static const struct { 68 _EGLPlatformType platform; 69 const char *name; 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" } 78 }; 79 80 81 /** 82 * Return the native platform by parsing EGL_PLATFORM. 83 */ 84 static _EGLPlatformType 85 _eglGetNativePlatformFromEnv(void) 86 { 87 _EGLPlatformType plat = _EGL_INVALID_PLATFORM; 88 const char *plat_name; 89 EGLint i; 90 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; 97 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; 101 break; 102 } 103 } 104 105 return plat; 106 } 107 108 109 /** 110 * Perform validity checks on a generic pointer. 111 */ 112 static EGLBoolean 113 _eglPointerIsDereferencable(void *p) 114 { 115 #ifdef HAVE_MINCORE 116 uintptr_t addr = (uintptr_t) p; 117 unsigned char valid = 0; 118 const long page_size = getpagesize(); 119 120 if (p == NULL) 121 return EGL_FALSE; 122 123 /* align addr to page_size */ 124 addr &= ~(page_size - 1); 125 126 if (mincore((void *) addr, page_size, &valid) < 0) { 127 _eglLog(_EGL_DEBUG, "mincore failed: %m"); 128 return EGL_FALSE; 129 } 130 131 return (valid & 0x01) == 0x01; 132 #else 133 return p != NULL; 134 #endif 135 } 136 137 138 /** 139 * Try detecting native platform with the help of native display characteristcs. 140 */ 141 static _EGLPlatformType 142 _eglNativePlatformDetectNativeDisplay(EGLNativeDisplayType nativeDisplay) 143 { 144 #ifdef HAVE_FBDEV_PLATFORM 145 struct stat buf; 146 #endif 147 148 if (nativeDisplay == EGL_DEFAULT_DISPLAY) 149 return _EGL_INVALID_PLATFORM; 150 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; 155 #endif 156 157 if (_eglPointerIsDereferencable(nativeDisplay)) { 158 void *first_pointer = *(void **) nativeDisplay; 159 160 (void) first_pointer; /* silence unused var warning */ 161 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; 167 #endif 168 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; 173 #endif 174 175 #ifdef HAVE_X11_PLATFORM 176 /* If not matched to any other platform, fallback to x11. */ 177 return _EGL_PLATFORM_X11; 178 #endif 179 } 180 181 return _EGL_INVALID_PLATFORM; 182 } 183 184 185 /** 186 * Return the native platform. It is the platform of the EGL native types. 187 */ 188 _EGLPlatformType 189 _eglGetNativePlatform(EGLNativeDisplayType nativeDisplay) 190 { 191 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM; 192 char *detection_method = NULL; 193 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"; 203 } 204 } 205 } 206 207 if (detection_method != NULL) 208 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)", 209 egl_platforms[native_platform].name, detection_method); 210 211 return native_platform; 212 } 213 214 215 /** 216 * Finish display management. 217 */ 218 void 219 _eglFiniDisplay(void) 220 { 221 _EGLDisplay *dpyList, *dpy; 222 223 /* atexit function is called with global mutex locked */ 224 dpyList = _eglGlobal.DisplayList; 225 while (dpyList) { 226 EGLint i; 227 228 /* pop list head */ 229 dpy = dpyList; 230 dpyList = dpyList->Next; 231 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); 235 break; 236 } 237 } 238 239 free(dpy); 240 } 241 _eglGlobal.DisplayList = NULL; 242 } 243 244 245 /** 246 * Find the display corresponding to the specified native display, or create a 247 * new one. 248 */ 249 _EGLDisplay * 250 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) 251 { 252 _EGLDisplay *dpy; 253 254 if (plat == _EGL_INVALID_PLATFORM) 255 return NULL; 256 257 _eglLockMutex(_eglGlobal.Mutex); 258 259 /* search the display list first */ 260 dpy = _eglGlobal.DisplayList; 261 while (dpy) { 262 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy) 263 break; 264 dpy = dpy->Next; 265 } 266 267 /* create a new display */ 268 if (!dpy) { 269 dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay)); 270 if (dpy) { 271 _eglInitMutex(&dpy->Mutex); 272 dpy->Platform = plat; 273 dpy->PlatformDisplay = plat_dpy; 274 275 /* add to the display list */ 276 dpy->Next = _eglGlobal.DisplayList; 277 _eglGlobal.DisplayList = dpy; 278 } 279 } 280 281 _eglUnlockMutex(_eglGlobal.Mutex); 282 283 return dpy; 284 } 285 286 287 /** 288 * Destroy the contexts and surfaces that are linked to the display. 289 */ 290 void 291 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display) 292 { 293 _EGLResource *list; 294 295 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT]; 296 while (list) { 297 _EGLContext *ctx = (_EGLContext *) list; 298 list = list->Next; 299 300 _eglUnlinkContext(ctx); 301 drv->API.DestroyContext(drv, display, ctx); 302 } 303 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]); 304 305 list = display->ResourceLists[_EGL_RESOURCE_SURFACE]; 306 while (list) { 307 _EGLSurface *surf = (_EGLSurface *) list; 308 list = list->Next; 309 310 _eglUnlinkSurface(surf); 311 drv->API.DestroySurface(drv, display, surf); 312 } 313 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]); 314 } 315 316 317 /** 318 * Free all the data hanging of an _EGLDisplay object, but not 319 * the object itself. 320 */ 321 void 322 _eglCleanupDisplay(_EGLDisplay *disp) 323 { 324 if (disp->Configs) { 325 _eglDestroyArray(disp->Configs, free); 326 disp->Configs = NULL; 327 } 328 329 /* XXX incomplete */ 330 } 331 332 333 /** 334 * Return EGL_TRUE if the given handle is a valid handle to a display. 335 */ 336 EGLBoolean 337 _eglCheckDisplayHandle(EGLDisplay dpy) 338 { 339 _EGLDisplay *cur; 340 341 _eglLockMutex(_eglGlobal.Mutex); 342 cur = _eglGlobal.DisplayList; 343 while (cur) { 344 if (cur == (_EGLDisplay *) dpy) 345 break; 346 cur = cur->Next; 347 } 348 _eglUnlockMutex(_eglGlobal.Mutex); 349 return (cur != NULL); 350 } 351 352 353 /** 354 * Return EGL_TRUE if the given resource is valid. That is, the display does 355 * own the resource. 356 */ 357 EGLBoolean 358 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy) 359 { 360 _EGLResource *list = dpy->ResourceLists[type]; 361 362 if (!res) 363 return EGL_FALSE; 364 365 while (list) { 366 if (res == (void *) list) { 367 assert(list->Display == dpy); 368 break; 369 } 370 list = list->Next; 371 } 372 373 return (list != NULL); 374 } 375 376 377 /** 378 * Initialize a display resource. 379 */ 380 void 381 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy) 382 { 383 memset(res, 0, size); 384 res->Display = dpy; 385 res->RefCount = 1; 386 } 387 388 389 /** 390 * Increment reference count for the resource. 391 */ 392 void 393 _eglGetResource(_EGLResource *res) 394 { 395 assert(res && res->RefCount > 0); 396 /* hopefully a resource is always manipulated with its display locked */ 397 res->RefCount++; 398 } 399 400 401 /** 402 * Decrement reference count for the resource. 403 */ 404 EGLBoolean 405 _eglPutResource(_EGLResource *res) 406 { 407 assert(res && res->RefCount > 0); 408 res->RefCount--; 409 return (!res->RefCount); 410 } 411 412 413 /** 414 * Link a resource to its display. 415 */ 416 void 417 _eglLinkResource(_EGLResource *res, _EGLResourceType type) 418 { 419 assert(res->Display); 420 421 res->IsLinked = EGL_TRUE; 422 res->Next = res->Display->ResourceLists[type]; 423 res->Display->ResourceLists[type] = res; 424 _eglGetResource(res); 425 } 426 427 428 /** 429 * Unlink a linked resource from its display. 430 */ 431 void 432 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type) 433 { 434 _EGLResource *prev; 435 436 prev = res->Display->ResourceLists[type]; 437 if (prev != res) { 438 while (prev) { 439 if (prev->Next == res) 440 break; 441 prev = prev->Next; 442 } 443 assert(prev); 444 prev->Next = res->Next; 445 } 446 else { 447 res->Display->ResourceLists[type] = res->Next; 448 } 449 450 res->Next = NULL; 451 res->IsLinked = EGL_FALSE; 452 _eglPutResource(res); 453 454 /* We always unlink before destroy. The driver still owns a reference */ 455 assert(res->RefCount); 456 } 457