Home | History | Annotate | Download | only in main
      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