1/************************************************************************** 2 * 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. 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 */ 67static 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 */ 84static _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 */ 112static 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 */ 141static _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 */ 218void 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 */ 290void 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 */ 321void 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 */ 336EGLBoolean 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 */ 357EGLBoolean 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 */ 380void 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 */ 392void 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 */ 404EGLBoolean 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 */ 416void 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 */ 431void 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