Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.  
  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.  
  48. /* Includes for _eglNativePlatformDetectNativeDisplay */
  49. #ifdef HAVE_MINCORE
  50. #include <unistd.h>
  51. #include <sys/mman.h>
  52. #endif
  53. #ifdef HAVE_WAYLAND_PLATFORM
  54. #include <wayland-client.h>
  55. #endif
  56. #ifdef HAVE_DRM_PLATFORM
  57. #include <gbm.h>
  58. #endif
  59.  
  60.  
  61. /**
  62.  * Map --with-egl-platforms names to platform types.
  63.  */
  64. static const struct {
  65.    _EGLPlatformType platform;
  66.    const char *name;
  67. } egl_platforms[_EGL_NUM_PLATFORMS] = {
  68.    { _EGL_PLATFORM_WINDOWS, "gdi" },
  69.    { _EGL_PLATFORM_X11, "x11" },
  70.    { _EGL_PLATFORM_WAYLAND, "wayland" },
  71.    { _EGL_PLATFORM_DRM, "drm" },
  72.    { _EGL_PLATFORM_NULL, "null" },
  73.    { _EGL_PLATFORM_ANDROID, "android" },
  74.    { _EGL_PLATFORM_HAIKU, "haiku" }
  75. };
  76.  
  77.  
  78. /**
  79.  * Return the native platform by parsing EGL_PLATFORM.
  80.  */
  81. static _EGLPlatformType
  82. _eglGetNativePlatformFromEnv(void)
  83. {
  84.    _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
  85.    const char *plat_name;
  86.    EGLint i;
  87.  
  88.    plat_name = getenv("EGL_PLATFORM");
  89.    /* try deprecated env variable */
  90.    if (!plat_name || !plat_name[0])
  91.       plat_name = getenv("EGL_DISPLAY");
  92.    if (!plat_name || !plat_name[0])
  93.       return _EGL_INVALID_PLATFORM;
  94.  
  95.    for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
  96.       if (strcmp(egl_platforms[i].name, plat_name) == 0) {
  97.          plat = egl_platforms[i].platform;
  98.          break;
  99.       }
  100.    }
  101.  
  102.    return plat;
  103. }
  104.  
  105.  
  106. /**
  107.  * Perform validity checks on a generic pointer.
  108.  */
  109. static EGLBoolean
  110. _eglPointerIsDereferencable(void *p)
  111. {
  112. #ifdef HAVE_MINCORE
  113.    uintptr_t addr = (uintptr_t) p;
  114.    unsigned char valid = 0;
  115.    const long page_size = getpagesize();
  116.  
  117.    if (p == NULL)
  118.       return EGL_FALSE;
  119.  
  120.    /* align addr to page_size */
  121.    addr &= ~(page_size - 1);
  122.  
  123.    if (mincore((void *) addr, page_size, &valid) < 0) {
  124.       _eglLog(_EGL_DEBUG, "mincore failed: %m");
  125.       return EGL_FALSE;
  126.    }
  127.  
  128.    return (valid & 0x01) == 0x01;
  129. #else
  130.    return p != NULL;
  131. #endif
  132. }
  133.  
  134.  
  135. /**
  136.  * Try detecting native platform with the help of native display characteristcs.
  137.  */
  138. static _EGLPlatformType
  139. _eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
  140. {
  141.    if (nativeDisplay == EGL_DEFAULT_DISPLAY)
  142.       return _EGL_INVALID_PLATFORM;
  143.  
  144.    if (_eglPointerIsDereferencable(nativeDisplay)) {
  145.       void *first_pointer = *(void **) nativeDisplay;
  146.  
  147.       (void) first_pointer; /* silence unused var warning */
  148.  
  149. #ifdef HAVE_WAYLAND_PLATFORM
  150.       /* wl_display is a wl_proxy, which is a wl_object.
  151.        * wl_object's first element points to the interfacetype. */
  152.       if (first_pointer == &wl_display_interface)
  153.          return _EGL_PLATFORM_WAYLAND;
  154. #endif
  155.  
  156. #ifdef HAVE_DRM_PLATFORM
  157.       /* gbm has a pointer to its constructor as first element. */
  158.       if (first_pointer == gbm_create_device)
  159.          return _EGL_PLATFORM_DRM;
  160. #endif
  161.  
  162. #ifdef HAVE_X11_PLATFORM
  163.       /* If not matched to any other platform, fallback to x11. */
  164.       return _EGL_PLATFORM_X11;
  165. #endif
  166.  
  167. #ifdef HAVE_HAIKU_PLATFORM
  168.         return _EGL_PLATFORM_HAIKU;
  169. #endif
  170.    }
  171.  
  172.    return _EGL_INVALID_PLATFORM;
  173. }
  174.  
  175.  
  176. /**
  177.  * Return the native platform.  It is the platform of the EGL native types.
  178.  */
  179. _EGLPlatformType
  180. _eglGetNativePlatform(void *nativeDisplay)
  181. {
  182.    static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
  183.    char *detection_method = NULL;
  184.  
  185.    if (native_platform == _EGL_INVALID_PLATFORM) {
  186.       native_platform = _eglGetNativePlatformFromEnv();
  187.       detection_method = "environment overwrite";
  188.       if (native_platform == _EGL_INVALID_PLATFORM) {
  189.          native_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
  190.          detection_method = "autodetected";
  191.          if (native_platform == _EGL_INVALID_PLATFORM) {
  192.             native_platform = _EGL_NATIVE_PLATFORM;
  193.             detection_method = "build-time configuration";
  194.          }
  195.       }
  196.    }
  197.  
  198.    if (detection_method != NULL)
  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.  
  307.  
  308. /**
  309.  * Free all the data hanging of an _EGLDisplay object, but not
  310.  * the object itself.
  311.  */
  312. void
  313. _eglCleanupDisplay(_EGLDisplay *disp)
  314. {
  315.    if (disp->Configs) {
  316.       _eglDestroyArray(disp->Configs, free);
  317.       disp->Configs = NULL;
  318.    }
  319.  
  320.    /* XXX incomplete */
  321. }
  322.  
  323.  
  324. /**
  325.  * Return EGL_TRUE if the given handle is a valid handle to a display.
  326.  */
  327. EGLBoolean
  328. _eglCheckDisplayHandle(EGLDisplay dpy)
  329. {
  330.    _EGLDisplay *cur;
  331.  
  332.    mtx_lock(_eglGlobal.Mutex);
  333.    cur = _eglGlobal.DisplayList;
  334.    while (cur) {
  335.       if (cur == (_EGLDisplay *) dpy)
  336.          break;
  337.       cur = cur->Next;
  338.    }
  339.    mtx_unlock(_eglGlobal.Mutex);
  340.    return (cur != NULL);
  341. }
  342.  
  343.  
  344. /**
  345.  * Return EGL_TRUE if the given resource is valid.  That is, the display does
  346.  * own the resource.
  347.  */
  348. EGLBoolean
  349. _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
  350. {
  351.    _EGLResource *list = dpy->ResourceLists[type];
  352.    
  353.    if (!res)
  354.       return EGL_FALSE;
  355.  
  356.    while (list) {
  357.       if (res == (void *) list) {
  358.          assert(list->Display == dpy);
  359.          break;
  360.       }
  361.       list = list->Next;
  362.    }
  363.  
  364.    return (list != NULL);
  365. }
  366.  
  367.  
  368. /**
  369.  * Initialize a display resource.  The size of the subclass object is
  370.  * specified.
  371.  *
  372.  * This is supposed to be called from the initializers of subclasses, such as
  373.  * _eglInitContext or _eglInitSurface.
  374.  */
  375. void
  376. _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
  377. {
  378.    memset(res, 0, size);
  379.    res->Display = dpy;
  380.    res->RefCount = 1;
  381. }
  382.  
  383.  
  384. /**
  385.  * Increment reference count for the resource.
  386.  */
  387. void
  388. _eglGetResource(_EGLResource *res)
  389. {
  390.    assert(res && res->RefCount > 0);
  391.    /* hopefully a resource is always manipulated with its display locked */
  392.    res->RefCount++;
  393. }
  394.  
  395.  
  396. /**
  397.  * Decrement reference count for the resource.
  398.  */
  399. EGLBoolean
  400. _eglPutResource(_EGLResource *res)
  401. {
  402.    assert(res && res->RefCount > 0);
  403.    res->RefCount--;
  404.    return (!res->RefCount);
  405. }
  406.  
  407.  
  408. /**
  409.  * Link a resource to its display.
  410.  */
  411. void
  412. _eglLinkResource(_EGLResource *res, _EGLResourceType type)
  413. {
  414.    assert(res->Display);
  415.  
  416.    res->IsLinked = EGL_TRUE;
  417.    res->Next = res->Display->ResourceLists[type];
  418.    res->Display->ResourceLists[type] = res;
  419.    _eglGetResource(res);
  420. }
  421.  
  422.  
  423. /**
  424.  * Unlink a linked resource from its display.
  425.  */
  426. void
  427. _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
  428. {
  429.    _EGLResource *prev;
  430.  
  431.    prev = res->Display->ResourceLists[type];
  432.    if (prev != res) {
  433.       while (prev) {
  434.          if (prev->Next == res)
  435.             break;
  436.          prev = prev->Next;
  437.       }
  438.       assert(prev);
  439.       prev->Next = res->Next;
  440.    }
  441.    else {
  442.       res->Display->ResourceLists[type] = res->Next;
  443.    }
  444.  
  445.    res->Next = NULL;
  446.    res->IsLinked = EGL_FALSE;
  447.    _eglPutResource(res);
  448.  
  449.    /* We always unlink before destroy.  The driver still owns a reference */
  450.    assert(res->RefCount);
  451. }
  452.  
  453. #ifdef HAVE_X11_PLATFORM
  454. static EGLBoolean
  455. _eglParseX11DisplayAttribList(const EGLint *attrib_list)
  456. {
  457.    int i;
  458.  
  459.    if (attrib_list == NULL) {
  460.       return EGL_TRUE;
  461.    }
  462.  
  463.    for (i = 0; attrib_list[i] != EGL_NONE; i += 2) {
  464.       EGLint attrib = attrib_list[i];
  465.       EGLint value = attrib_list[i + 1];
  466.  
  467.       /* EGL_EXT_platform_x11 recognizes exactly one attribute,
  468.        * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
  469.        *
  470.        * Mesa supports connecting to only the default screen, so we reject
  471.        * screen != 0.
  472.        */
  473.       if (attrib != EGL_PLATFORM_X11_SCREEN_EXT || value != 0) {
  474.          _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  475.          return EGL_FALSE;
  476.       }
  477.    }
  478.  
  479.    return EGL_TRUE;
  480. }
  481.  
  482. _EGLDisplay*
  483. _eglGetX11Display(Display *native_display,
  484.                   const EGLint *attrib_list)
  485. {
  486.    if (!_eglParseX11DisplayAttribList(attrib_list)) {
  487.       return NULL;
  488.    }
  489.  
  490.    return _eglFindDisplay(_EGL_PLATFORM_X11, native_display);
  491. }
  492. #endif /* HAVE_X11_PLATFORM */
  493.  
  494. #ifdef HAVE_DRM_PLATFORM
  495. _EGLDisplay*
  496. _eglGetGbmDisplay(struct gbm_device *native_display,
  497.                   const EGLint *attrib_list)
  498. {
  499.    /* EGL_MESA_platform_gbm recognizes no attributes. */
  500.    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  501.       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  502.       return NULL;
  503.    }
  504.  
  505.    return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display);
  506. }
  507. #endif /* HAVE_DRM_PLATFORM */
  508.  
  509. #ifdef HAVE_WAYLAND_PLATFORM
  510. _EGLDisplay*
  511. _eglGetWaylandDisplay(struct wl_display *native_display,
  512.                       const EGLint *attrib_list)
  513. {
  514.    /* EGL_EXT_platform_wayland recognizes no attributes. */
  515.    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  516.       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  517.       return NULL;
  518.    }
  519.  
  520.    return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display);
  521. }
  522. #endif /* HAVE_WAYLAND_PLATFORM */
  523.