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