"Fossies" - the Fresh Open Source Software Archive

Member "mesa-20.1.8/src/egl/main/egldisplay.c" (16 Sep 2020, 16656 Bytes) of package /linux/misc/mesa-20.1.8.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "egldisplay.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20.1.5_vs_20.2.0-rc1.

    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 <unistd.h>
   39 #include <fcntl.h>
   40 #include "c11/threads.h"
   41 #include "util/macros.h"
   42 #include "util/u_atomic.h"
   43 
   44 #include "eglcontext.h"
   45 #include "eglcurrent.h"
   46 #include "eglsurface.h"
   47 #include "egldevice.h"
   48 #include "egldisplay.h"
   49 #include "egldriver.h"
   50 #include "eglglobals.h"
   51 #include "egllog.h"
   52 #include "eglimage.h"
   53 #include "eglsync.h"
   54 
   55 /* Includes for _eglNativePlatformDetectNativeDisplay */
   56 #ifdef HAVE_WAYLAND_PLATFORM
   57 #include <wayland-client.h>
   58 #endif
   59 #ifdef HAVE_DRM_PLATFORM
   60 #include <gbm.h>
   61 #endif
   62 
   63 
   64 /**
   65  * Map build-system platform names to platform types.
   66  */
   67 static const struct {
   68    _EGLPlatformType platform;
   69    const char *name;
   70 } egl_platforms[] = {
   71    { _EGL_PLATFORM_X11, "x11" },
   72    { _EGL_PLATFORM_WAYLAND, "wayland" },
   73    { _EGL_PLATFORM_DRM, "drm" },
   74    { _EGL_PLATFORM_ANDROID, "android" },
   75    { _EGL_PLATFORM_HAIKU, "haiku" },
   76    { _EGL_PLATFORM_SURFACELESS, "surfaceless" },
   77    { _EGL_PLATFORM_DEVICE, "device" },
   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    static_assert(ARRAY_SIZE(egl_platforms) == _EGL_NUM_PLATFORMS,
   92                  "Missing platform");
   93 
   94    plat_name = getenv("EGL_PLATFORM");
   95    /* try deprecated env variable */
   96    if (!plat_name || !plat_name[0])
   97       plat_name = getenv("EGL_DISPLAY");
   98    if (!plat_name || !plat_name[0])
   99       return _EGL_INVALID_PLATFORM;
  100 
  101    for (i = 0; i < ARRAY_SIZE(egl_platforms); i++) {
  102       if (strcmp(egl_platforms[i].name, plat_name) == 0) {
  103          plat = egl_platforms[i].platform;
  104          break;
  105       }
  106    }
  107 
  108    if (plat == _EGL_INVALID_PLATFORM)
  109       _eglLog(_EGL_WARNING, "invalid EGL_PLATFORM given");
  110 
  111    return plat;
  112 }
  113 
  114 
  115 /**
  116  * Try detecting native platform with the help of native display characteristcs.
  117  */
  118 static _EGLPlatformType
  119 _eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
  120 {
  121    if (nativeDisplay == EGL_DEFAULT_DISPLAY)
  122       return _EGL_INVALID_PLATFORM;
  123 
  124    if (_eglPointerIsDereferencable(nativeDisplay)) {
  125       void *first_pointer = *(void **) nativeDisplay;
  126 
  127       (void) first_pointer; /* silence unused var warning */
  128 
  129 #ifdef HAVE_WAYLAND_PLATFORM
  130       /* wl_display is a wl_proxy, which is a wl_object.
  131        * wl_object's first element points to the interfacetype. */
  132       if (first_pointer == &wl_display_interface)
  133          return _EGL_PLATFORM_WAYLAND;
  134 #endif
  135 
  136 #ifdef HAVE_DRM_PLATFORM
  137       /* gbm has a pointer to its constructor as first element. */
  138       if (first_pointer == gbm_create_device)
  139          return _EGL_PLATFORM_DRM;
  140 #endif
  141    }
  142 
  143    return _EGL_INVALID_PLATFORM;
  144 }
  145 
  146 
  147 /**
  148  * Return the native platform.  It is the platform of the EGL native types.
  149  */
  150 _EGLPlatformType
  151 _eglGetNativePlatform(void *nativeDisplay)
  152 {
  153    _EGLPlatformType detected_platform = _eglGetNativePlatformFromEnv();
  154    const char *detection_method = "environment";
  155 
  156    if (detected_platform == _EGL_INVALID_PLATFORM) {
  157       detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
  158       detection_method = "autodetected";
  159    }
  160 
  161    if (detected_platform == _EGL_INVALID_PLATFORM) {
  162       detected_platform = _EGL_NATIVE_PLATFORM;
  163       detection_method = "build-time configuration";
  164    }
  165 
  166    _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
  167            egl_platforms[detected_platform].name, detection_method);
  168 
  169    return detected_platform;
  170 }
  171 
  172 
  173 /**
  174  * Finish display management.
  175  */
  176 void
  177 _eglFiniDisplay(void)
  178 {
  179    _EGLDisplay *dispList, *disp;
  180 
  181    /* atexit function is called with global mutex locked */
  182    dispList = _eglGlobal.DisplayList;
  183    while (dispList) {
  184       EGLint i;
  185 
  186       /* pop list head */
  187       disp = dispList;
  188       dispList = dispList->Next;
  189 
  190       for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
  191          if (disp->ResourceLists[i]) {
  192             _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
  193             break;
  194          }
  195       }
  196 
  197 
  198       /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
  199        * and invalid one is 0.
  200        */
  201       if (disp->Options.fd)
  202          close(disp->Options.fd);
  203 
  204       free(disp->Options.Attribs);
  205       free(disp);
  206    }
  207    _eglGlobal.DisplayList = NULL;
  208 }
  209 
  210 static EGLBoolean
  211 _eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b)
  212 {
  213    size_t na = _eglNumAttribs(a);
  214    size_t nb = _eglNumAttribs(b);
  215 
  216    /* different numbers of attributes must be different */
  217    if (na != nb)
  218       return EGL_FALSE;
  219 
  220    /* both lists NULL are the same */
  221    if (!a && !b)
  222       return EGL_TRUE;
  223 
  224    /* otherwise, compare the lists */
  225    return memcmp(a, b, na * sizeof(a[0])) == 0 ? EGL_TRUE : EGL_FALSE;
  226 }
  227 
  228 /**
  229  * Find the display corresponding to the specified native display, or create a
  230  * new one. EGL 1.5 says:
  231  *
  232  *     Multiple calls made to eglGetPlatformDisplay with the same parameters
  233  *     will return the same EGLDisplay handle.
  234  *
  235  * We read this extremely strictly, and treat a call with NULL attribs as
  236  * different from a call with attribs only equal to { EGL_NONE }. Similarly
  237  * we do not sort the attribute list, so even if all attribute _values_ are
  238  * identical, different attribute orders will be considered different
  239  * parameters.
  240  */
  241 _EGLDisplay *
  242 _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy,
  243                 const EGLAttrib *attrib_list)
  244 {
  245    _EGLDisplay *disp;
  246    size_t num_attribs;
  247 
  248    if (plat == _EGL_INVALID_PLATFORM)
  249       return NULL;
  250 
  251    mtx_lock(_eglGlobal.Mutex);
  252 
  253    /* search the display list first */
  254    for (disp = _eglGlobal.DisplayList; disp; disp = disp->Next) {
  255       if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy &&
  256           _eglSameAttribs(disp->Options.Attribs, attrib_list))
  257          break;
  258    }
  259 
  260    /* create a new display */
  261    if (!disp) {
  262       disp = calloc(1, sizeof(_EGLDisplay));
  263       if (disp) {
  264          mtx_init(&disp->Mutex, mtx_plain);
  265          disp->Platform = plat;
  266          disp->PlatformDisplay = plat_dpy;
  267          num_attribs = _eglNumAttribs(attrib_list);
  268          if (num_attribs) {
  269             disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib));
  270             if (!disp->Options.Attribs) {
  271                free(disp);
  272                disp = NULL;
  273                goto out;
  274             }
  275             memcpy(disp->Options.Attribs, attrib_list,
  276                    num_attribs * sizeof(EGLAttrib));
  277          }
  278          /* add to the display list */
  279          disp->Next = _eglGlobal.DisplayList;
  280          _eglGlobal.DisplayList = disp;
  281       }
  282    }
  283 
  284 out:
  285    mtx_unlock(_eglGlobal.Mutex);
  286 
  287    return disp;
  288 }
  289 
  290 
  291 /**
  292  * Destroy the contexts and surfaces that are linked to the display.
  293  */
  294 void
  295 _eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
  296 {
  297    _EGLResource *list;
  298 
  299    list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
  300    while (list) {
  301       _EGLContext *ctx = (_EGLContext *) list;
  302       list = list->Next;
  303 
  304       _eglUnlinkContext(ctx);
  305       drv->API.DestroyContext(drv, display, ctx);
  306    }
  307    assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
  308 
  309    list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
  310    while (list) {
  311       _EGLSurface *surf = (_EGLSurface *) list;
  312       list = list->Next;
  313 
  314       _eglUnlinkSurface(surf);
  315       drv->API.DestroySurface(drv, display, surf);
  316    }
  317    assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
  318 
  319    list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
  320    while (list) {
  321       _EGLImage *image = (_EGLImage *) list;
  322       list = list->Next;
  323 
  324       _eglUnlinkImage(image);
  325       drv->API.DestroyImageKHR(drv, display, image);
  326    }
  327    assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
  328 
  329    list = display->ResourceLists[_EGL_RESOURCE_SYNC];
  330    while (list) {
  331       _EGLSync *sync = (_EGLSync *) list;
  332       list = list->Next;
  333 
  334       _eglUnlinkSync(sync);
  335       drv->API.DestroySyncKHR(drv, display, sync);
  336    }
  337    assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
  338 }
  339 
  340 
  341 /**
  342  * Free all the data hanging of an _EGLDisplay object, but not
  343  * the object itself.
  344  */
  345 void
  346 _eglCleanupDisplay(_EGLDisplay *disp)
  347 {
  348    if (disp->Configs) {
  349       _eglDestroyArray(disp->Configs, free);
  350       disp->Configs = NULL;
  351    }
  352 
  353    /* XXX incomplete */
  354 }
  355 
  356 
  357 /**
  358  * Return EGL_TRUE if the given handle is a valid handle to a display.
  359  */
  360 EGLBoolean
  361 _eglCheckDisplayHandle(EGLDisplay dpy)
  362 {
  363    _EGLDisplay *cur;
  364 
  365    mtx_lock(_eglGlobal.Mutex);
  366    cur = _eglGlobal.DisplayList;
  367    while (cur) {
  368       if (cur == (_EGLDisplay *) dpy)
  369          break;
  370       cur = cur->Next;
  371    }
  372    mtx_unlock(_eglGlobal.Mutex);
  373    return (cur != NULL);
  374 }
  375 
  376 
  377 /**
  378  * Return EGL_TRUE if the given resource is valid.  That is, the display does
  379  * own the resource.
  380  */
  381 EGLBoolean
  382 _eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
  383 {
  384    _EGLResource *list = disp->ResourceLists[type];
  385    
  386    if (!res)
  387       return EGL_FALSE;
  388 
  389    while (list) {
  390       if (res == (void *) list) {
  391          assert(list->Display == disp);
  392          break;
  393       }
  394       list = list->Next;
  395    }
  396 
  397    return (list != NULL);
  398 }
  399 
  400 
  401 /**
  402  * Initialize a display resource.  The size of the subclass object is
  403  * specified.
  404  *
  405  * This is supposed to be called from the initializers of subclasses, such as
  406  * _eglInitContext or _eglInitSurface.
  407  */
  408 void
  409 _eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
  410 {
  411    memset(res, 0, size);
  412    res->Display = disp;
  413    res->RefCount = 1;
  414 }
  415 
  416 
  417 /**
  418  * Increment reference count for the resource.
  419  */
  420 void
  421 _eglGetResource(_EGLResource *res)
  422 {
  423    assert(res && res->RefCount > 0);
  424    /* hopefully a resource is always manipulated with its display locked */
  425    res->RefCount++;
  426 }
  427 
  428 
  429 /**
  430  * Decrement reference count for the resource.
  431  */
  432 EGLBoolean
  433 _eglPutResource(_EGLResource *res)
  434 {
  435    assert(res && res->RefCount > 0);
  436    res->RefCount--;
  437    return (!res->RefCount);
  438 }
  439 
  440 
  441 /**
  442  * Link a resource to its display.
  443  */
  444 void
  445 _eglLinkResource(_EGLResource *res, _EGLResourceType type)
  446 {
  447    assert(res->Display);
  448 
  449    res->IsLinked = EGL_TRUE;
  450    res->Next = res->Display->ResourceLists[type];
  451    res->Display->ResourceLists[type] = res;
  452    _eglGetResource(res);
  453 }
  454 
  455 
  456 /**
  457  * Unlink a linked resource from its display.
  458  */
  459 void
  460 _eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
  461 {
  462    _EGLResource *prev;
  463 
  464    prev = res->Display->ResourceLists[type];
  465    if (prev != res) {
  466       while (prev) {
  467          if (prev->Next == res)
  468             break;
  469          prev = prev->Next;
  470       }
  471       assert(prev);
  472       prev->Next = res->Next;
  473    }
  474    else {
  475       res->Display->ResourceLists[type] = res->Next;
  476    }
  477 
  478    res->Next = NULL;
  479    res->IsLinked = EGL_FALSE;
  480    _eglPutResource(res);
  481 
  482    /* We always unlink before destroy.  The driver still owns a reference */
  483    assert(res->RefCount);
  484 }
  485 
  486 #ifdef HAVE_X11_PLATFORM
  487 _EGLDisplay*
  488 _eglGetX11Display(Display *native_display,
  489                   const EGLAttrib *attrib_list)
  490 {
  491    /* EGL_EXT_platform_x11 recognizes exactly one attribute,
  492     * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
  493     */
  494    if (attrib_list != NULL) {
  495       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
  496          if (attrib_list[i] != EGL_PLATFORM_X11_SCREEN_EXT) {
  497             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  498             return NULL;
  499          }
  500       }
  501    }
  502    return _eglFindDisplay(_EGL_PLATFORM_X11, native_display, attrib_list);
  503 }
  504 #endif /* HAVE_X11_PLATFORM */
  505 
  506 #ifdef HAVE_DRM_PLATFORM
  507 _EGLDisplay*
  508 _eglGetGbmDisplay(struct gbm_device *native_display,
  509                   const EGLAttrib *attrib_list)
  510 {
  511    /* EGL_MESA_platform_gbm recognizes no attributes. */
  512    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  513       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  514       return NULL;
  515    }
  516 
  517    return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list);
  518 }
  519 #endif /* HAVE_DRM_PLATFORM */
  520 
  521 #ifdef HAVE_WAYLAND_PLATFORM
  522 _EGLDisplay*
  523 _eglGetWaylandDisplay(struct wl_display *native_display,
  524                       const EGLAttrib *attrib_list)
  525 {
  526    /* EGL_EXT_platform_wayland recognizes no attributes. */
  527    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  528       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  529       return NULL;
  530    }
  531 
  532    return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list);
  533 }
  534 #endif /* HAVE_WAYLAND_PLATFORM */
  535 
  536 #ifdef HAVE_SURFACELESS_PLATFORM
  537 _EGLDisplay*
  538 _eglGetSurfacelessDisplay(void *native_display,
  539                           const EGLAttrib *attrib_list)
  540 {
  541    /* This platform has no native display. */
  542    if (native_display != NULL) {
  543       _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
  544       return NULL;
  545    }
  546 
  547    /* This platform recognizes no display attributes. */
  548    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  549       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  550       return NULL;
  551    }
  552 
  553    return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display,
  554                           attrib_list);
  555 }
  556 #endif /* HAVE_SURFACELESS_PLATFORM */
  557 
  558 #ifdef HAVE_ANDROID_PLATFORM
  559 _EGLDisplay*
  560 _eglGetAndroidDisplay(void *native_display,
  561                           const EGLAttrib *attrib_list)
  562 {
  563 
  564    /* This platform recognizes no display attributes. */
  565    if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
  566       _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  567       return NULL;
  568    }
  569 
  570    return _eglFindDisplay(_EGL_PLATFORM_ANDROID, native_display,
  571                           attrib_list);
  572 }
  573 #endif /* HAVE_ANDROID_PLATFORM */
  574 
  575 _EGLDisplay*
  576 _eglGetDeviceDisplay(void *native_display,
  577                      const EGLAttrib *attrib_list)
  578 {
  579    _EGLDevice *dev;
  580    _EGLDisplay *display;
  581    int fd = -1;
  582 
  583    dev = _eglLookupDevice(native_display);
  584    if (!dev) {
  585       _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
  586       return NULL;
  587    }
  588 
  589    if (attrib_list) {
  590       for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
  591          EGLAttrib attrib = attrib_list[i];
  592          EGLAttrib value = attrib_list[i + 1];
  593 
  594          /* EGL_EXT_platform_device does not recognize any attributes,
  595           * EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
  596           */
  597 
  598          if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
  599              attrib != EGL_DRM_MASTER_FD_EXT) {
  600             _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
  601             return NULL;
  602          }
  603 
  604          fd = (int) value;
  605       }
  606    }
  607 
  608    display = _eglFindDisplay(_EGL_PLATFORM_DEVICE, native_display, attrib_list);
  609    if (!display) {
  610       _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
  611       return NULL;
  612    }
  613 
  614    /* If the fd is explicitly provided and we did not dup() it yet, do so.
  615     * The spec mandates that we do so, since we'll need it past the
  616     * eglGetPlatformDispay call.
  617     *
  618     * The new fd is guaranteed to be 3 or greater.
  619     */
  620    if (fd != -1 && display->Options.fd == 0) {
  621       display->Options.fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
  622       if (display->Options.fd == -1) {
  623          /* Do not (really) need to teardown the display */
  624          _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
  625          return NULL;
  626       }
  627    }
  628 
  629    return display;
  630 }