egldisplay.c revision 848b8605
1/************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 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 "eglcurrent.h" 40#include "eglsurface.h" 41#include "egldisplay.h" 42#include "egldriver.h" 43#include "eglglobals.h" 44#include "eglmutex.h" 45#include "egllog.h" 46 47/* Includes for _eglNativePlatformDetectNativeDisplay */ 48#ifdef HAVE_MINCORE 49#include <unistd.h> 50#include <sys/mman.h> 51#endif 52#ifdef HAVE_WAYLAND_PLATFORM 53#include <wayland-client.h> 54#endif 55#ifdef HAVE_DRM_PLATFORM 56#include <gbm.h> 57#endif 58#ifdef HAVE_FBDEV_PLATFORM 59#include <stdint.h> 60#include <sys/types.h> 61#include <sys/stat.h> 62#endif 63 64 65/** 66 * Map --with-egl-platforms names to platform types. 67 */ 68static const struct { 69 _EGLPlatformType platform; 70 const char *name; 71} egl_platforms[_EGL_NUM_PLATFORMS] = { 72 { _EGL_PLATFORM_WINDOWS, "gdi" }, 73 { _EGL_PLATFORM_X11, "x11" }, 74 { _EGL_PLATFORM_WAYLAND, "wayland" }, 75 { _EGL_PLATFORM_DRM, "drm" }, 76 { _EGL_PLATFORM_FBDEV, "fbdev" }, 77 { _EGL_PLATFORM_NULL, "null" }, 78 { _EGL_PLATFORM_ANDROID, "android" } 79}; 80 81 82/** 83 * Return the native platform by parsing EGL_PLATFORM. 84 */ 85static _EGLPlatformType 86_eglGetNativePlatformFromEnv(void) 87{ 88 _EGLPlatformType plat = _EGL_INVALID_PLATFORM; 89 const char *plat_name; 90 EGLint i; 91 92 plat_name = getenv("EGL_PLATFORM"); 93 /* try deprecated env variable */ 94 if (!plat_name || !plat_name[0]) 95 plat_name = getenv("EGL_DISPLAY"); 96 if (!plat_name || !plat_name[0]) 97 return _EGL_INVALID_PLATFORM; 98 99 for (i = 0; i < _EGL_NUM_PLATFORMS; i++) { 100 if (strcmp(egl_platforms[i].name, plat_name) == 0) { 101 plat = egl_platforms[i].platform; 102 break; 103 } 104 } 105 106 return plat; 107} 108 109 110/** 111 * Perform validity checks on a generic pointer. 112 */ 113static EGLBoolean 114_eglPointerIsDereferencable(void *p) 115{ 116#ifdef HAVE_MINCORE 117 uintptr_t addr = (uintptr_t) p; 118 unsigned char valid = 0; 119 const long page_size = getpagesize(); 120 121 if (p == NULL) 122 return EGL_FALSE; 123 124 /* align addr to page_size */ 125 addr &= ~(page_size - 1); 126 127 if (mincore((void *) addr, page_size, &valid) < 0) { 128 _eglLog(_EGL_DEBUG, "mincore failed: %m"); 129 return EGL_FALSE; 130 } 131 132 return (valid & 0x01) == 0x01; 133#else 134 return p != NULL; 135#endif 136} 137 138 139/** 140 * Try detecting native platform with the help of native display characteristcs. 141 */ 142static _EGLPlatformType 143_eglNativePlatformDetectNativeDisplay(void *nativeDisplay) 144{ 145#ifdef HAVE_FBDEV_PLATFORM 146 struct stat buf; 147#endif 148 149 if (nativeDisplay == EGL_DEFAULT_DISPLAY) 150 return _EGL_INVALID_PLATFORM; 151 152#ifdef HAVE_FBDEV_PLATFORM 153 /* fbdev is the only platform that can be a file descriptor. */ 154 if (fstat((intptr_t) nativeDisplay, &buf) == 0 && S_ISCHR(buf.st_mode)) 155 return _EGL_PLATFORM_FBDEV; 156#endif 157 158 if (_eglPointerIsDereferencable(nativeDisplay)) { 159 void *first_pointer = *(void **) nativeDisplay; 160 161 (void) first_pointer; /* silence unused var warning */ 162 163#ifdef HAVE_WAYLAND_PLATFORM 164 /* wl_display is a wl_proxy, which is a wl_object. 165 * wl_object's first element points to the interfacetype. */ 166 if (first_pointer == &wl_display_interface) 167 return _EGL_PLATFORM_WAYLAND; 168#endif 169 170#ifdef HAVE_DRM_PLATFORM 171 /* gbm has a pointer to its constructor as first element. */ 172 if (first_pointer == gbm_create_device) 173 return _EGL_PLATFORM_DRM; 174#endif 175 176#ifdef HAVE_X11_PLATFORM 177 /* If not matched to any other platform, fallback to x11. */ 178 return _EGL_PLATFORM_X11; 179#endif 180 } 181 182 return _EGL_INVALID_PLATFORM; 183} 184 185 186/** 187 * Return the native platform. It is the platform of the EGL native types. 188 */ 189_EGLPlatformType 190_eglGetNativePlatform(void *nativeDisplay) 191{ 192 static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM; 193 char *detection_method = NULL; 194 195 if (native_platform == _EGL_INVALID_PLATFORM) { 196 native_platform = _eglGetNativePlatformFromEnv(); 197 detection_method = "environment overwrite"; 198 if (native_platform == _EGL_INVALID_PLATFORM) { 199 native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay); 200 detection_method = "autodetected"; 201 if (native_platform == _EGL_INVALID_PLATFORM) { 202 native_platform = _EGL_NATIVE_PLATFORM; 203 detection_method = "build-time configuration"; 204 } 205 } 206 } 207 208 if (detection_method != NULL) 209 _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)", 210 egl_platforms[native_platform].name, detection_method); 211 212 return native_platform; 213} 214 215 216/** 217 * Finish display management. 218 */ 219void 220_eglFiniDisplay(void) 221{ 222 _EGLDisplay *dpyList, *dpy; 223 224 /* atexit function is called with global mutex locked */ 225 dpyList = _eglGlobal.DisplayList; 226 while (dpyList) { 227 EGLint i; 228 229 /* pop list head */ 230 dpy = dpyList; 231 dpyList = dpyList->Next; 232 233 for (i = 0; i < _EGL_NUM_RESOURCES; i++) { 234 if (dpy->ResourceLists[i]) { 235 _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy); 236 break; 237 } 238 } 239 240 free(dpy); 241 } 242 _eglGlobal.DisplayList = NULL; 243} 244 245 246/** 247 * Find the display corresponding to the specified native display, or create a 248 * new one. 249 */ 250_EGLDisplay * 251_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) 252{ 253 _EGLDisplay *dpy; 254 255 if (plat == _EGL_INVALID_PLATFORM) 256 return NULL; 257 258 _eglLockMutex(_eglGlobal.Mutex); 259 260 /* search the display list first */ 261 dpy = _eglGlobal.DisplayList; 262 while (dpy) { 263 if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy) 264 break; 265 dpy = dpy->Next; 266 } 267 268 /* create a new display */ 269 if (!dpy) { 270 dpy = calloc(1, sizeof(_EGLDisplay)); 271 if (dpy) { 272 _eglInitMutex(&dpy->Mutex); 273 dpy->Platform = plat; 274 dpy->PlatformDisplay = plat_dpy; 275 276 /* add to the display list */ 277 dpy->Next = _eglGlobal.DisplayList; 278 _eglGlobal.DisplayList = dpy; 279 } 280 } 281 282 _eglUnlockMutex(_eglGlobal.Mutex); 283 284 return dpy; 285} 286 287 288/** 289 * Destroy the contexts and surfaces that are linked to the display. 290 */ 291void 292_eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display) 293{ 294 _EGLResource *list; 295 296 list = display->ResourceLists[_EGL_RESOURCE_CONTEXT]; 297 while (list) { 298 _EGLContext *ctx = (_EGLContext *) list; 299 list = list->Next; 300 301 _eglUnlinkContext(ctx); 302 drv->API.DestroyContext(drv, display, ctx); 303 } 304 assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]); 305 306 list = display->ResourceLists[_EGL_RESOURCE_SURFACE]; 307 while (list) { 308 _EGLSurface *surf = (_EGLSurface *) list; 309 list = list->Next; 310 311 _eglUnlinkSurface(surf); 312 drv->API.DestroySurface(drv, display, surf); 313 } 314 assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]); 315} 316 317 318/** 319 * Free all the data hanging of an _EGLDisplay object, but not 320 * the object itself. 321 */ 322void 323_eglCleanupDisplay(_EGLDisplay *disp) 324{ 325 if (disp->Configs) { 326 _eglDestroyArray(disp->Configs, free); 327 disp->Configs = NULL; 328 } 329 330 /* XXX incomplete */ 331} 332 333 334/** 335 * Return EGL_TRUE if the given handle is a valid handle to a display. 336 */ 337EGLBoolean 338_eglCheckDisplayHandle(EGLDisplay dpy) 339{ 340 _EGLDisplay *cur; 341 342 _eglLockMutex(_eglGlobal.Mutex); 343 cur = _eglGlobal.DisplayList; 344 while (cur) { 345 if (cur == (_EGLDisplay *) dpy) 346 break; 347 cur = cur->Next; 348 } 349 _eglUnlockMutex(_eglGlobal.Mutex); 350 return (cur != NULL); 351} 352 353 354/** 355 * Return EGL_TRUE if the given resource is valid. That is, the display does 356 * own the resource. 357 */ 358EGLBoolean 359_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy) 360{ 361 _EGLResource *list = dpy->ResourceLists[type]; 362 363 if (!res) 364 return EGL_FALSE; 365 366 while (list) { 367 if (res == (void *) list) { 368 assert(list->Display == dpy); 369 break; 370 } 371 list = list->Next; 372 } 373 374 return (list != NULL); 375} 376 377 378/** 379 * Initialize a display resource. The size of the subclass object is 380 * specified. 381 * 382 * This is supposed to be called from the initializers of subclasses, such as 383 * _eglInitContext or _eglInitSurface. 384 */ 385void 386_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy) 387{ 388 memset(res, 0, size); 389 res->Display = dpy; 390 res->RefCount = 1; 391} 392 393 394/** 395 * Increment reference count for the resource. 396 */ 397void 398_eglGetResource(_EGLResource *res) 399{ 400 assert(res && res->RefCount > 0); 401 /* hopefully a resource is always manipulated with its display locked */ 402 res->RefCount++; 403} 404 405 406/** 407 * Decrement reference count for the resource. 408 */ 409EGLBoolean 410_eglPutResource(_EGLResource *res) 411{ 412 assert(res && res->RefCount > 0); 413 res->RefCount--; 414 return (!res->RefCount); 415} 416 417 418/** 419 * Link a resource to its display. 420 */ 421void 422_eglLinkResource(_EGLResource *res, _EGLResourceType type) 423{ 424 assert(res->Display); 425 426 res->IsLinked = EGL_TRUE; 427 res->Next = res->Display->ResourceLists[type]; 428 res->Display->ResourceLists[type] = res; 429 _eglGetResource(res); 430} 431 432 433/** 434 * Unlink a linked resource from its display. 435 */ 436void 437_eglUnlinkResource(_EGLResource *res, _EGLResourceType type) 438{ 439 _EGLResource *prev; 440 441 prev = res->Display->ResourceLists[type]; 442 if (prev != res) { 443 while (prev) { 444 if (prev->Next == res) 445 break; 446 prev = prev->Next; 447 } 448 assert(prev); 449 prev->Next = res->Next; 450 } 451 else { 452 res->Display->ResourceLists[type] = res->Next; 453 } 454 455 res->Next = NULL; 456 res->IsLinked = EGL_FALSE; 457 _eglPutResource(res); 458 459 /* We always unlink before destroy. The driver still owns a reference */ 460 assert(res->RefCount); 461} 462 463#ifdef HAVE_X11_PLATFORM 464static EGLBoolean 465_eglParseX11DisplayAttribList(const EGLint *attrib_list) 466{ 467 int i; 468 469 if (attrib_list == NULL) { 470 return EGL_TRUE; 471 } 472 473 for (i = 0; attrib_list[i] != EGL_NONE; i += 2) { 474 EGLint attrib = attrib_list[i]; 475 EGLint value = attrib_list[i + 1]; 476 477 /* EGL_EXT_platform_x11 recognizes exactly one attribute, 478 * EGL_PLATFORM_X11_SCREEN_EXT, which is optional. 479 * 480 * Mesa supports connecting to only the default screen, so we reject 481 * screen != 0. 482 */ 483 if (attrib != EGL_PLATFORM_X11_SCREEN_EXT || value != 0) { 484 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); 485 return EGL_FALSE; 486 } 487 } 488 489 return EGL_TRUE; 490} 491 492_EGLDisplay* 493_eglGetX11Display(Display *native_display, 494 const EGLint *attrib_list) 495{ 496 if (!_eglParseX11DisplayAttribList(attrib_list)) { 497 return NULL; 498 } 499 500 return _eglFindDisplay(_EGL_PLATFORM_X11, native_display); 501} 502#endif /* HAVE_X11_PLATFORM */ 503 504#ifdef HAVE_DRM_PLATFORM 505_EGLDisplay* 506_eglGetGbmDisplay(struct gbm_device *native_display, 507 const EGLint *attrib_list) 508{ 509 /* EGL_MESA_platform_gbm recognizes no attributes. */ 510 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) { 511 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); 512 return NULL; 513 } 514 515 return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display); 516} 517#endif /* HAVE_DRM_PLATFORM */ 518 519#ifdef HAVE_WAYLAND_PLATFORM 520_EGLDisplay* 521_eglGetWaylandDisplay(struct wl_display *native_display, 522 const EGLint *attrib_list) 523{ 524 /* EGL_EXT_platform_wayland recognizes no attributes. */ 525 if (attrib_list != NULL && attrib_list[0] != EGL_NONE) { 526 _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); 527 return NULL; 528 } 529 530 return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display); 531} 532#endif /* HAVE_WAYLAND_PLATFORM */ 533