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 #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 --with-platforms names to platform types.
     62  */
     63 static 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  */
     79 static _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  */
    107 static _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  */
    184 void
    185 _eglFiniDisplay(void)
    186 {
    187    _EGLDisplay *dpyList, *dpy;
    188 
    189    /* atexit function is called with global mutex locked */
    190    dpyList = _eglGlobal.DisplayList;
    191    while (dpyList) {
    192       EGLint i;
    193 
    194       /* pop list head */
    195       dpy = dpyList;
    196       dpyList = dpyList->Next;
    197 
    198       for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
    199          if (dpy->ResourceLists[i]) {
    200             _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
    201             break;
    202          }
    203       }
    204 
    205       free(dpy);
    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 *dpy;
    219 
    220    if (plat == _EGL_INVALID_PLATFORM)
    221       return NULL;
    222 
    223    mtx_lock(_eglGlobal.Mutex);
    224 
    225    /* search the display list first */
    226    dpy = _eglGlobal.DisplayList;
    227    while (dpy) {
    228       if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
    229          break;
    230       dpy = dpy->Next;
    231    }
    232 
    233    /* create a new display */
    234    if (!dpy) {
    235       dpy = calloc(1, sizeof(_EGLDisplay));
    236       if (dpy) {
    237          mtx_init(&dpy->Mutex, mtx_plain);
    238          dpy->Platform = plat;
    239          dpy->PlatformDisplay = plat_dpy;
    240 
    241          /* add to the display list */
    242          dpy->Next = _eglGlobal.DisplayList;
    243          _eglGlobal.DisplayList = dpy;
    244       }
    245    }
    246 
    247    mtx_unlock(_eglGlobal.Mutex);
    248 
    249    return dpy;
    250 }
    251 
    252 
    253 /**
    254  * Destroy the contexts and surfaces that are linked to the display.
    255  */
    256 void
    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  */
    307 void
    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  */
    322 EGLBoolean
    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  */
    343 EGLBoolean
    344 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
    345 {
    346    _EGLResource *list = dpy->ResourceLists[type];
    347 
    348    if (!res)
    349       return EGL_FALSE;
    350 
    351    while (list) {
    352       if (res == (void *) list) {
    353          assert(list->Display == dpy);
    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  */
    370 void
    371 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
    372 {
    373    memset(res, 0, size);
    374    res->Display = dpy;
    375    res->RefCount = 1;
    376 }
    377 
    378 
    379 /**
    380  * Increment reference count for the resource.
    381  */
    382 void
    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  */
    394 EGLBoolean
    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  */
    406 void
    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  */
    421 void
    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
    449 static 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