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