13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
3af69d88dSmrg * Copyright 2008 VMware, Inc.
43464ebd5Sriastradh * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
53464ebd5Sriastradh * Copyright 2010-2011 LunarG, Inc.
63464ebd5Sriastradh * All Rights Reserved.
73464ebd5Sriastradh *
83464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a
93464ebd5Sriastradh * copy of this software and associated documentation files (the
103464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including
113464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish,
123464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to
133464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to
143464ebd5Sriastradh * the following conditions:
153464ebd5Sriastradh *
163464ebd5Sriastradh * The above copyright notice and this permission notice (including the
173464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions
183464ebd5Sriastradh * of the Software.
193464ebd5Sriastradh *
203464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
213464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
223464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
233464ebd5Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
243464ebd5Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
253464ebd5Sriastradh * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
263464ebd5Sriastradh * DEALINGS IN THE SOFTWARE.
273464ebd5Sriastradh *
283464ebd5Sriastradh **************************************************************************/
293464ebd5Sriastradh
303464ebd5Sriastradh
314a49301eSmrg/**
324a49301eSmrg * Functions related to EGLDisplay.
334a49301eSmrg */
344a49301eSmrg
354a49301eSmrg#include <assert.h>
364a49301eSmrg#include <stdlib.h>
374a49301eSmrg#include <string.h>
387ec681f3Smrg#ifdef _WIN32
397ec681f3Smrg#include <io.h>
407ec681f3Smrg#else
417ec681f3Smrg#include <unistd.h>
427ec681f3Smrg#endif
437ec681f3Smrg#include <fcntl.h>
4401e04c3fSmrg#include "c11/threads.h"
457ec681f3Smrg#include "util/macros.h"
467ec681f3Smrg#include "util/os_file.h"
4701e04c3fSmrg#include "util/u_atomic.h"
4801e04c3fSmrg
494a49301eSmrg#include "eglcontext.h"
50af69d88dSmrg#include "eglcurrent.h"
514a49301eSmrg#include "eglsurface.h"
527ec681f3Smrg#include "egldevice.h"
534a49301eSmrg#include "egldisplay.h"
544a49301eSmrg#include "egldriver.h"
554a49301eSmrg#include "eglglobals.h"
564a49301eSmrg#include "egllog.h"
5701e04c3fSmrg#include "eglimage.h"
5801e04c3fSmrg#include "eglsync.h"
594a49301eSmrg
60af69d88dSmrg/* Includes for _eglNativePlatformDetectNativeDisplay */
61af69d88dSmrg#ifdef HAVE_WAYLAND_PLATFORM
62af69d88dSmrg#include <wayland-client.h>
63af69d88dSmrg#endif
64af69d88dSmrg#ifdef HAVE_DRM_PLATFORM
65af69d88dSmrg#include <gbm.h>
66af69d88dSmrg#endif
677ec681f3Smrg#ifdef HAVE_WINDOWS_PLATFORM
687ec681f3Smrg#include <windows.h>
697ec681f3Smrg#endif
70af69d88dSmrg
71af69d88dSmrg
72af69d88dSmrg/**
737e102996Smaya * Map build-system platform names to platform types.
74af69d88dSmrg */
75af69d88dSmrgstatic const struct {
76af69d88dSmrg   _EGLPlatformType platform;
77af69d88dSmrg   const char *name;
787ec681f3Smrg} egl_platforms[] = {
79af69d88dSmrg   { _EGL_PLATFORM_X11, "x11" },
807ec681f3Smrg   { _EGL_PLATFORM_XCB, "xcb" },
81af69d88dSmrg   { _EGL_PLATFORM_WAYLAND, "wayland" },
82af69d88dSmrg   { _EGL_PLATFORM_DRM, "drm" },
8301e04c3fSmrg   { _EGL_PLATFORM_ANDROID, "android" },
8401e04c3fSmrg   { _EGL_PLATFORM_HAIKU, "haiku" },
8501e04c3fSmrg   { _EGL_PLATFORM_SURFACELESS, "surfaceless" },
867ec681f3Smrg   { _EGL_PLATFORM_DEVICE, "device" },
877ec681f3Smrg   { _EGL_PLATFORM_WINDOWS, "windows" },
88af69d88dSmrg};
89af69d88dSmrg
904a49301eSmrg
913464ebd5Sriastradh/**
923464ebd5Sriastradh * Return the native platform by parsing EGL_PLATFORM.
933464ebd5Sriastradh */
943464ebd5Sriastradhstatic _EGLPlatformType
953464ebd5Sriastradh_eglGetNativePlatformFromEnv(void)
963464ebd5Sriastradh{
973464ebd5Sriastradh   _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
983464ebd5Sriastradh   const char *plat_name;
993464ebd5Sriastradh   EGLint i;
1003464ebd5Sriastradh
1017ec681f3Smrg   static_assert(ARRAY_SIZE(egl_platforms) == _EGL_NUM_PLATFORMS,
1027ec681f3Smrg                 "Missing platform");
1037ec681f3Smrg
1043464ebd5Sriastradh   plat_name = getenv("EGL_PLATFORM");
1053464ebd5Sriastradh   /* try deprecated env variable */
1063464ebd5Sriastradh   if (!plat_name || !plat_name[0])
1073464ebd5Sriastradh      plat_name = getenv("EGL_DISPLAY");
1083464ebd5Sriastradh   if (!plat_name || !plat_name[0])
1093464ebd5Sriastradh      return _EGL_INVALID_PLATFORM;
1103464ebd5Sriastradh
1117ec681f3Smrg   for (i = 0; i < ARRAY_SIZE(egl_platforms); i++) {
1123464ebd5Sriastradh      if (strcmp(egl_platforms[i].name, plat_name) == 0) {
1133464ebd5Sriastradh         plat = egl_platforms[i].platform;
1143464ebd5Sriastradh         break;
1153464ebd5Sriastradh      }
1163464ebd5Sriastradh   }
1173464ebd5Sriastradh
1187ec681f3Smrg   if (plat == _EGL_INVALID_PLATFORM)
1197ec681f3Smrg      _eglLog(_EGL_WARNING, "invalid EGL_PLATFORM given");
1207ec681f3Smrg
1213464ebd5Sriastradh   return plat;
1223464ebd5Sriastradh}
1233464ebd5Sriastradh
1243464ebd5Sriastradh
125af69d88dSmrg/**
126af69d88dSmrg * Try detecting native platform with the help of native display characteristcs.
127af69d88dSmrg */
128af69d88dSmrgstatic _EGLPlatformType
129af69d88dSmrg_eglNativePlatformDetectNativeDisplay(void *nativeDisplay)
130af69d88dSmrg{
131af69d88dSmrg   if (nativeDisplay == EGL_DEFAULT_DISPLAY)
132af69d88dSmrg      return _EGL_INVALID_PLATFORM;
133af69d88dSmrg
1347ec681f3Smrg#ifdef HAVE_WINDOWS_PLATFORM
1357ec681f3Smrg   if (GetObjectType(nativeDisplay) == OBJ_DC)
1367ec681f3Smrg      return _EGL_PLATFORM_WINDOWS;
1377ec681f3Smrg#endif
1387ec681f3Smrg
1397ec681f3Smrg#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM)
140af69d88dSmrg   if (_eglPointerIsDereferencable(nativeDisplay)) {
141af69d88dSmrg      void *first_pointer = *(void **) nativeDisplay;
142af69d88dSmrg
143af69d88dSmrg#ifdef HAVE_WAYLAND_PLATFORM
144af69d88dSmrg      /* wl_display is a wl_proxy, which is a wl_object.
145af69d88dSmrg       * wl_object's first element points to the interfacetype. */
146af69d88dSmrg      if (first_pointer == &wl_display_interface)
147af69d88dSmrg         return _EGL_PLATFORM_WAYLAND;
148af69d88dSmrg#endif
149af69d88dSmrg
150af69d88dSmrg#ifdef HAVE_DRM_PLATFORM
151af69d88dSmrg      /* gbm has a pointer to its constructor as first element. */
152af69d88dSmrg      if (first_pointer == gbm_create_device)
153af69d88dSmrg         return _EGL_PLATFORM_DRM;
154af69d88dSmrg#endif
155af69d88dSmrg   }
1567ec681f3Smrg#endif
157af69d88dSmrg
158af69d88dSmrg   return _EGL_INVALID_PLATFORM;
159af69d88dSmrg}
160af69d88dSmrg
161af69d88dSmrg
1623464ebd5Sriastradh/**
1633464ebd5Sriastradh * Return the native platform.  It is the platform of the EGL native types.
1643464ebd5Sriastradh */
1653464ebd5Sriastradh_EGLPlatformType
166af69d88dSmrg_eglGetNativePlatform(void *nativeDisplay)
1673464ebd5Sriastradh{
1687ec681f3Smrg   _EGLPlatformType detected_platform = _eglGetNativePlatformFromEnv();
1697ec681f3Smrg   const char *detection_method = "environment";
17001e04c3fSmrg
17101e04c3fSmrg   if (detected_platform == _EGL_INVALID_PLATFORM) {
1727ec681f3Smrg      detected_platform = _eglNativePlatformDetectNativeDisplay(nativeDisplay);
1737ec681f3Smrg      detection_method = "autodetected";
1747ec681f3Smrg   }
17501e04c3fSmrg
1767ec681f3Smrg   if (detected_platform == _EGL_INVALID_PLATFORM) {
1777ec681f3Smrg      detected_platform = _EGL_NATIVE_PLATFORM;
1787ec681f3Smrg      detection_method = "build-time configuration";
17901e04c3fSmrg   }
180af69d88dSmrg
1817ec681f3Smrg   _eglLog(_EGL_DEBUG, "Native platform type: %s (%s)",
1827ec681f3Smrg           egl_platforms[detected_platform].name, detection_method);
1837ec681f3Smrg
1847ec681f3Smrg   return detected_platform;
1853464ebd5Sriastradh}
1863464ebd5Sriastradh
1873464ebd5Sriastradh
1884a49301eSmrg/**
1894a49301eSmrg * Finish display management.
1904a49301eSmrg */
1914a49301eSmrgvoid
1924a49301eSmrg_eglFiniDisplay(void)
1934a49301eSmrg{
1947e102996Smaya   _EGLDisplay *dispList, *disp;
1954a49301eSmrg
1964a49301eSmrg   /* atexit function is called with global mutex locked */
1977e102996Smaya   dispList = _eglGlobal.DisplayList;
1987e102996Smaya   while (dispList) {
199cdc920a0Smrg      EGLint i;
200cdc920a0Smrg
2014a49301eSmrg      /* pop list head */
2027e102996Smaya      disp = dispList;
2037e102996Smaya      dispList = dispList->Next;
2044a49301eSmrg
205cdc920a0Smrg      for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
2067e102996Smaya         if (disp->ResourceLists[i]) {
2077e102996Smaya            _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", disp);
208cdc920a0Smrg            break;
209cdc920a0Smrg         }
210cdc920a0Smrg      }
2114a49301eSmrg
2127ec681f3Smrg
2137ec681f3Smrg      /* The fcntl() code in _eglGetDeviceDisplay() ensures that valid fd >= 3,
2147ec681f3Smrg       * and invalid one is 0.
2157ec681f3Smrg       */
2167ec681f3Smrg      if (disp->Options.fd)
2177ec681f3Smrg         close(disp->Options.fd);
2187ec681f3Smrg
2197ec681f3Smrg      free(disp->Options.Attribs);
2207e102996Smaya      free(disp);
2214a49301eSmrg   }
2224a49301eSmrg   _eglGlobal.DisplayList = NULL;
2234a49301eSmrg}
2244a49301eSmrg
2257ec681f3Smrgstatic EGLBoolean
2267ec681f3Smrg_eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b)
2277ec681f3Smrg{
2287ec681f3Smrg   size_t na = _eglNumAttribs(a);
2297ec681f3Smrg   size_t nb = _eglNumAttribs(b);
2307ec681f3Smrg
2317ec681f3Smrg   /* different numbers of attributes must be different */
2327ec681f3Smrg   if (na != nb)
2337ec681f3Smrg      return EGL_FALSE;
2347ec681f3Smrg
2357ec681f3Smrg   /* both lists NULL are the same */
2367ec681f3Smrg   if (!a && !b)
2377ec681f3Smrg      return EGL_TRUE;
2387ec681f3Smrg
2397ec681f3Smrg   /* otherwise, compare the lists */
2407ec681f3Smrg   return memcmp(a, b, na * sizeof(a[0])) == 0 ? EGL_TRUE : EGL_FALSE;
2417ec681f3Smrg}
2424a49301eSmrg
2434a49301eSmrg/**
244cdc920a0Smrg * Find the display corresponding to the specified native display, or create a
2457ec681f3Smrg * new one. EGL 1.5 says:
2467ec681f3Smrg *
2477ec681f3Smrg *     Multiple calls made to eglGetPlatformDisplay with the same parameters
2487ec681f3Smrg *     will return the same EGLDisplay handle.
2497ec681f3Smrg *
2507ec681f3Smrg * We read this extremely strictly, and treat a call with NULL attribs as
2517ec681f3Smrg * different from a call with attribs only equal to { EGL_NONE }. Similarly
2527ec681f3Smrg * we do not sort the attribute list, so even if all attribute _values_ are
2537ec681f3Smrg * identical, different attribute orders will be considered different
2547ec681f3Smrg * parameters.
2554a49301eSmrg */
2564a49301eSmrg_EGLDisplay *
2577ec681f3Smrg_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy,
2587ec681f3Smrg                const EGLAttrib *attrib_list)
2594a49301eSmrg{
2607e102996Smaya   _EGLDisplay *disp;
2617ec681f3Smrg   size_t num_attribs;
2624a49301eSmrg
2633464ebd5Sriastradh   if (plat == _EGL_INVALID_PLATFORM)
2643464ebd5Sriastradh      return NULL;
2653464ebd5Sriastradh
26601e04c3fSmrg   mtx_lock(_eglGlobal.Mutex);
2674a49301eSmrg
268cdc920a0Smrg   /* search the display list first */
2697ec681f3Smrg   for (disp = _eglGlobal.DisplayList; disp; disp = disp->Next) {
2707ec681f3Smrg      if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy &&
2717ec681f3Smrg          _eglSameAttribs(disp->Options.Attribs, attrib_list))
2727ec681f3Smrg         goto out;
2734a49301eSmrg   }
2744a49301eSmrg
275cdc920a0Smrg   /* create a new display */
2767ec681f3Smrg   assert(!disp);
2777ec681f3Smrg   disp = calloc(1, sizeof(_EGLDisplay));
2787ec681f3Smrg   if (!disp)
2797ec681f3Smrg      goto out;
2807ec681f3Smrg
2817ec681f3Smrg   mtx_init(&disp->Mutex, mtx_plain);
2827ec681f3Smrg   disp->Platform = plat;
2837ec681f3Smrg   disp->PlatformDisplay = plat_dpy;
2847ec681f3Smrg   num_attribs = _eglNumAttribs(attrib_list);
2857ec681f3Smrg   if (num_attribs) {
2867ec681f3Smrg      disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib));
2877ec681f3Smrg      if (!disp->Options.Attribs) {
2887ec681f3Smrg         free(disp);
2897ec681f3Smrg         disp = NULL;
2907ec681f3Smrg         goto out;
291cdc920a0Smrg      }
2927ec681f3Smrg      memcpy(disp->Options.Attribs, attrib_list,
2937ec681f3Smrg             num_attribs * sizeof(EGLAttrib));
294cdc920a0Smrg   }
295cdc920a0Smrg
2967ec681f3Smrg   /* add to the display list */
2977ec681f3Smrg   disp->Next = _eglGlobal.DisplayList;
2987ec681f3Smrg   _eglGlobal.DisplayList = disp;
2997ec681f3Smrg
3007ec681f3Smrgout:
30101e04c3fSmrg   mtx_unlock(_eglGlobal.Mutex);
3024a49301eSmrg
3037e102996Smaya   return disp;
3044a49301eSmrg}
3054a49301eSmrg
3064a49301eSmrg
3074a49301eSmrg/**
3084a49301eSmrg * Destroy the contexts and surfaces that are linked to the display.
3094a49301eSmrg */
3104a49301eSmrgvoid
3117ec681f3Smrg_eglReleaseDisplayResources(_EGLDisplay *display)
3124a49301eSmrg{
313cdc920a0Smrg   _EGLResource *list;
3147ec681f3Smrg   const _EGLDriver *drv = display->Driver;
3154a49301eSmrg
316cdc920a0Smrg   list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
317cdc920a0Smrg   while (list) {
318cdc920a0Smrg      _EGLContext *ctx = (_EGLContext *) list;
319cdc920a0Smrg      list = list->Next;
3204a49301eSmrg
3214a49301eSmrg      _eglUnlinkContext(ctx);
3227ec681f3Smrg      drv->DestroyContext(display, ctx);
3234a49301eSmrg   }
324cdc920a0Smrg   assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
3254a49301eSmrg
326cdc920a0Smrg   list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
327cdc920a0Smrg   while (list) {
328cdc920a0Smrg      _EGLSurface *surf = (_EGLSurface *) list;
329cdc920a0Smrg      list = list->Next;
3304a49301eSmrg
3314a49301eSmrg      _eglUnlinkSurface(surf);
3327ec681f3Smrg      drv->DestroySurface(display, surf);
3334a49301eSmrg   }
334cdc920a0Smrg   assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
33501e04c3fSmrg
33601e04c3fSmrg   list = display->ResourceLists[_EGL_RESOURCE_IMAGE];
33701e04c3fSmrg   while (list) {
33801e04c3fSmrg      _EGLImage *image = (_EGLImage *) list;
33901e04c3fSmrg      list = list->Next;
34001e04c3fSmrg
34101e04c3fSmrg      _eglUnlinkImage(image);
3427ec681f3Smrg      drv->DestroyImageKHR(display, image);
34301e04c3fSmrg   }
34401e04c3fSmrg   assert(!display->ResourceLists[_EGL_RESOURCE_IMAGE]);
34501e04c3fSmrg
34601e04c3fSmrg   list = display->ResourceLists[_EGL_RESOURCE_SYNC];
34701e04c3fSmrg   while (list) {
34801e04c3fSmrg      _EGLSync *sync = (_EGLSync *) list;
34901e04c3fSmrg      list = list->Next;
35001e04c3fSmrg
35101e04c3fSmrg      _eglUnlinkSync(sync);
3527ec681f3Smrg      drv->DestroySyncKHR(display, sync);
35301e04c3fSmrg   }
35401e04c3fSmrg   assert(!display->ResourceLists[_EGL_RESOURCE_SYNC]);
3554a49301eSmrg}
3564a49301eSmrg
3574a49301eSmrg
3584a49301eSmrg/**
3594a49301eSmrg * Free all the data hanging of an _EGLDisplay object, but not
3604a49301eSmrg * the object itself.
3614a49301eSmrg */
3624a49301eSmrgvoid
3634a49301eSmrg_eglCleanupDisplay(_EGLDisplay *disp)
3644a49301eSmrg{
3654a49301eSmrg   if (disp->Configs) {
3663464ebd5Sriastradh      _eglDestroyArray(disp->Configs, free);
3674a49301eSmrg      disp->Configs = NULL;
3684a49301eSmrg   }
3694a49301eSmrg
3704a49301eSmrg   /* XXX incomplete */
3714a49301eSmrg}
3724a49301eSmrg
3734a49301eSmrg
3744a49301eSmrg/**
3754a49301eSmrg * Return EGL_TRUE if the given handle is a valid handle to a display.
3764a49301eSmrg */
3774a49301eSmrgEGLBoolean
3784a49301eSmrg_eglCheckDisplayHandle(EGLDisplay dpy)
3794a49301eSmrg{
3804a49301eSmrg   _EGLDisplay *cur;
3814a49301eSmrg
38201e04c3fSmrg   mtx_lock(_eglGlobal.Mutex);
3834a49301eSmrg   cur = _eglGlobal.DisplayList;
3844a49301eSmrg   while (cur) {
3854a49301eSmrg      if (cur == (_EGLDisplay *) dpy)
3864a49301eSmrg         break;
3874a49301eSmrg      cur = cur->Next;
3884a49301eSmrg   }
38901e04c3fSmrg   mtx_unlock(_eglGlobal.Mutex);
3904a49301eSmrg   return (cur != NULL);
3914a49301eSmrg}
3924a49301eSmrg
3934a49301eSmrg
3944a49301eSmrg/**
395cdc920a0Smrg * Return EGL_TRUE if the given resource is valid.  That is, the display does
396cdc920a0Smrg * own the resource.
3974a49301eSmrg */
3984a49301eSmrgEGLBoolean
3997e102996Smaya_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *disp)
4004a49301eSmrg{
4017e102996Smaya   _EGLResource *list = disp->ResourceLists[type];
402cdc920a0Smrg
403cdc920a0Smrg   if (!res)
404cdc920a0Smrg      return EGL_FALSE;
405cdc920a0Smrg
406cdc920a0Smrg   while (list) {
407cdc920a0Smrg      if (res == (void *) list) {
4087e102996Smaya         assert(list->Display == disp);
4094a49301eSmrg         break;
4104a49301eSmrg      }
411cdc920a0Smrg      list = list->Next;
4124a49301eSmrg   }
413cdc920a0Smrg
414cdc920a0Smrg   return (list != NULL);
4154a49301eSmrg}
4164a49301eSmrg
4174a49301eSmrg
4184a49301eSmrg/**
419af69d88dSmrg * Initialize a display resource.  The size of the subclass object is
420af69d88dSmrg * specified.
421af69d88dSmrg *
422af69d88dSmrg * This is supposed to be called from the initializers of subclasses, such as
423af69d88dSmrg * _eglInitContext or _eglInitSurface.
4244a49301eSmrg */
425cdc920a0Smrgvoid
4267e102996Smaya_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *disp)
4274a49301eSmrg{
4283464ebd5Sriastradh   memset(res, 0, size);
4297e102996Smaya   res->Display = disp;
4303464ebd5Sriastradh   res->RefCount = 1;
4313464ebd5Sriastradh}
4323464ebd5Sriastradh
4333464ebd5Sriastradh
4343464ebd5Sriastradh/**
4353464ebd5Sriastradh * Increment reference count for the resource.
4363464ebd5Sriastradh */
4373464ebd5Sriastradhvoid
4383464ebd5Sriastradh_eglGetResource(_EGLResource *res)
4393464ebd5Sriastradh{
4403464ebd5Sriastradh   assert(res && res->RefCount > 0);
4413464ebd5Sriastradh   /* hopefully a resource is always manipulated with its display locked */
4423464ebd5Sriastradh   res->RefCount++;
4433464ebd5Sriastradh}
4443464ebd5Sriastradh
4453464ebd5Sriastradh
4463464ebd5Sriastradh/**
4473464ebd5Sriastradh * Decrement reference count for the resource.
4483464ebd5Sriastradh */
4493464ebd5SriastradhEGLBoolean
4503464ebd5Sriastradh_eglPutResource(_EGLResource *res)
4513464ebd5Sriastradh{
4523464ebd5Sriastradh   assert(res && res->RefCount > 0);
4533464ebd5Sriastradh   res->RefCount--;
4543464ebd5Sriastradh   return (!res->RefCount);
4553464ebd5Sriastradh}
4563464ebd5Sriastradh
4573464ebd5Sriastradh
4583464ebd5Sriastradh/**
4593464ebd5Sriastradh * Link a resource to its display.
4603464ebd5Sriastradh */
4613464ebd5Sriastradhvoid
4623464ebd5Sriastradh_eglLinkResource(_EGLResource *res, _EGLResourceType type)
4633464ebd5Sriastradh{
4643464ebd5Sriastradh   assert(res->Display);
4653464ebd5Sriastradh
466cdc920a0Smrg   res->IsLinked = EGL_TRUE;
4673464ebd5Sriastradh   res->Next = res->Display->ResourceLists[type];
4683464ebd5Sriastradh   res->Display->ResourceLists[type] = res;
4693464ebd5Sriastradh   _eglGetResource(res);
4704a49301eSmrg}
4714a49301eSmrg
4724a49301eSmrg
473cdc920a0Smrg/**
474cdc920a0Smrg * Unlink a linked resource from its display.
475cdc920a0Smrg */
476cdc920a0Smrgvoid
477cdc920a0Smrg_eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
478cdc920a0Smrg{
479cdc920a0Smrg   _EGLResource *prev;
480cdc920a0Smrg
481cdc920a0Smrg   prev = res->Display->ResourceLists[type];
482cdc920a0Smrg   if (prev != res) {
483cdc920a0Smrg      while (prev) {
484cdc920a0Smrg         if (prev->Next == res)
485cdc920a0Smrg            break;
486cdc920a0Smrg         prev = prev->Next;
487cdc920a0Smrg      }
488cdc920a0Smrg      assert(prev);
489cdc920a0Smrg      prev->Next = res->Next;
490cdc920a0Smrg   }
491cdc920a0Smrg   else {
492cdc920a0Smrg      res->Display->ResourceLists[type] = res->Next;
493cdc920a0Smrg   }
494cdc920a0Smrg
495cdc920a0Smrg   res->Next = NULL;
496cdc920a0Smrg   res->IsLinked = EGL_FALSE;
4973464ebd5Sriastradh   _eglPutResource(res);
4983464ebd5Sriastradh
4993464ebd5Sriastradh   /* We always unlink before destroy.  The driver still owns a reference */
5003464ebd5Sriastradh   assert(res->RefCount);
501cdc920a0Smrg}
502af69d88dSmrg
503af69d88dSmrg#ifdef HAVE_X11_PLATFORM
5047ec681f3Smrg_EGLDisplay*
5057ec681f3Smrg_eglGetX11Display(Display *native_display,
5067ec681f3Smrg                  const EGLAttrib *attrib_list)
507af69d88dSmrg{
5087ec681f3Smrg   /* EGL_EXT_platform_x11 recognizes exactly one attribute,
5097ec681f3Smrg    * EGL_PLATFORM_X11_SCREEN_EXT, which is optional.
5107ec681f3Smrg    */
5117ec681f3Smrg   if (attrib_list != NULL) {
5127ec681f3Smrg      for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
5137ec681f3Smrg         if (attrib_list[i] != EGL_PLATFORM_X11_SCREEN_EXT) {
5147ec681f3Smrg            _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
5157ec681f3Smrg            return NULL;
5167ec681f3Smrg         }
5177ec681f3Smrg      }
518af69d88dSmrg   }
5197ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_X11, native_display, attrib_list);
520af69d88dSmrg}
5217ec681f3Smrg#endif /* HAVE_X11_PLATFORM */
522af69d88dSmrg
5237ec681f3Smrg#ifdef HAVE_XCB_PLATFORM
524af69d88dSmrg_EGLDisplay*
5257ec681f3Smrg_eglGetXcbDisplay(xcb_connection_t *native_display,
52601e04c3fSmrg                  const EGLAttrib *attrib_list)
527af69d88dSmrg{
5287ec681f3Smrg   /* EGL_EXT_platform_xcb recognizes exactly one attribute,
5297ec681f3Smrg    * EGL_PLATFORM_XCB_SCREEN_EXT, which is optional.
5307ec681f3Smrg    */
5317ec681f3Smrg   if (attrib_list != NULL) {
5327ec681f3Smrg      for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
5337ec681f3Smrg         if (attrib_list[i] != EGL_PLATFORM_XCB_SCREEN_EXT) {
5347ec681f3Smrg            _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
5357ec681f3Smrg            return NULL;
5367ec681f3Smrg         }
5377ec681f3Smrg      }
53801e04c3fSmrg   }
53901e04c3fSmrg
5407ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_XCB, native_display, attrib_list);
541af69d88dSmrg}
5427ec681f3Smrg#endif /* HAVE_XCB_PLATFORM */
543af69d88dSmrg
544af69d88dSmrg#ifdef HAVE_DRM_PLATFORM
545af69d88dSmrg_EGLDisplay*
546af69d88dSmrg_eglGetGbmDisplay(struct gbm_device *native_display,
54701e04c3fSmrg                  const EGLAttrib *attrib_list)
548af69d88dSmrg{
549af69d88dSmrg   /* EGL_MESA_platform_gbm recognizes no attributes. */
550af69d88dSmrg   if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
551af69d88dSmrg      _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
552af69d88dSmrg      return NULL;
553af69d88dSmrg   }
554af69d88dSmrg
5557ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list);
556af69d88dSmrg}
557af69d88dSmrg#endif /* HAVE_DRM_PLATFORM */
558af69d88dSmrg
559af69d88dSmrg#ifdef HAVE_WAYLAND_PLATFORM
560af69d88dSmrg_EGLDisplay*
561af69d88dSmrg_eglGetWaylandDisplay(struct wl_display *native_display,
56201e04c3fSmrg                      const EGLAttrib *attrib_list)
563af69d88dSmrg{
564af69d88dSmrg   /* EGL_EXT_platform_wayland recognizes no attributes. */
565af69d88dSmrg   if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
566af69d88dSmrg      _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
567af69d88dSmrg      return NULL;
568af69d88dSmrg   }
569af69d88dSmrg
5707ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list);
571af69d88dSmrg}
572af69d88dSmrg#endif /* HAVE_WAYLAND_PLATFORM */
57301e04c3fSmrg
57401e04c3fSmrg_EGLDisplay*
57501e04c3fSmrg_eglGetSurfacelessDisplay(void *native_display,
57601e04c3fSmrg                          const EGLAttrib *attrib_list)
57701e04c3fSmrg{
57801e04c3fSmrg   /* This platform has no native display. */
57901e04c3fSmrg   if (native_display != NULL) {
58001e04c3fSmrg      _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
58101e04c3fSmrg      return NULL;
58201e04c3fSmrg   }
58301e04c3fSmrg
58401e04c3fSmrg   /* This platform recognizes no display attributes. */
58501e04c3fSmrg   if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
58601e04c3fSmrg      _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
58701e04c3fSmrg      return NULL;
58801e04c3fSmrg   }
58901e04c3fSmrg
5907ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display,
5917ec681f3Smrg                          attrib_list);
5927ec681f3Smrg}
5937ec681f3Smrg
5947ec681f3Smrg#ifdef HAVE_ANDROID_PLATFORM
5957ec681f3Smrg_EGLDisplay*
5967ec681f3Smrg_eglGetAndroidDisplay(void *native_display,
5977ec681f3Smrg                          const EGLAttrib *attrib_list)
5987ec681f3Smrg{
5997ec681f3Smrg
6007ec681f3Smrg   /* This platform recognizes no display attributes. */
6017ec681f3Smrg   if (attrib_list != NULL && attrib_list[0] != EGL_NONE) {
6027ec681f3Smrg      _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
6037ec681f3Smrg      return NULL;
6047ec681f3Smrg   }
6057ec681f3Smrg
6067ec681f3Smrg   return _eglFindDisplay(_EGL_PLATFORM_ANDROID, native_display,
6077ec681f3Smrg                          attrib_list);
6087ec681f3Smrg}
6097ec681f3Smrg#endif /* HAVE_ANDROID_PLATFORM */
6107ec681f3Smrg
6117ec681f3Smrg_EGLDisplay*
6127ec681f3Smrg_eglGetDeviceDisplay(void *native_display,
6137ec681f3Smrg                     const EGLAttrib *attrib_list)
6147ec681f3Smrg{
6157ec681f3Smrg   _EGLDevice *dev;
6167ec681f3Smrg   _EGLDisplay *display;
6177ec681f3Smrg   int fd = -1;
6187ec681f3Smrg
6197ec681f3Smrg   dev = _eglLookupDevice(native_display);
6207ec681f3Smrg   if (!dev) {
6217ec681f3Smrg      _eglError(EGL_BAD_PARAMETER, "eglGetPlatformDisplay");
6227ec681f3Smrg      return NULL;
6237ec681f3Smrg   }
6247ec681f3Smrg
6257ec681f3Smrg   if (attrib_list) {
6267ec681f3Smrg      for (int i = 0; attrib_list[i] != EGL_NONE; i += 2) {
6277ec681f3Smrg         EGLAttrib attrib = attrib_list[i];
6287ec681f3Smrg         EGLAttrib value = attrib_list[i + 1];
6297ec681f3Smrg
6307ec681f3Smrg         /* EGL_EXT_platform_device does not recognize any attributes,
6317ec681f3Smrg          * EGL_EXT_device_drm adds the optional EGL_DRM_MASTER_FD_EXT.
6327ec681f3Smrg          */
6337ec681f3Smrg
6347ec681f3Smrg         if (!_eglDeviceSupports(dev, _EGL_DEVICE_DRM) ||
6357ec681f3Smrg             attrib != EGL_DRM_MASTER_FD_EXT) {
6367ec681f3Smrg            _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay");
6377ec681f3Smrg            return NULL;
6387ec681f3Smrg         }
6397ec681f3Smrg
6407ec681f3Smrg         fd = (int) value;
6417ec681f3Smrg      }
6427ec681f3Smrg   }
6437ec681f3Smrg
6447ec681f3Smrg   display = _eglFindDisplay(_EGL_PLATFORM_DEVICE, native_display, attrib_list);
6457ec681f3Smrg   if (!display) {
6467ec681f3Smrg      _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
6477ec681f3Smrg      return NULL;
6487ec681f3Smrg   }
6497ec681f3Smrg
6507ec681f3Smrg   /* If the fd is explicitly provided and we did not dup() it yet, do so.
6517ec681f3Smrg    * The spec mandates that we do so, since we'll need it past the
6527ec681f3Smrg    * eglGetPlatformDispay call.
6537ec681f3Smrg    *
6547ec681f3Smrg    * The new fd is guaranteed to be 3 or greater.
6557ec681f3Smrg    */
6567ec681f3Smrg   if (fd != -1 && display->Options.fd == 0) {
6577ec681f3Smrg      display->Options.fd = os_dupfd_cloexec(fd);
6587ec681f3Smrg      if (display->Options.fd == -1) {
6597ec681f3Smrg         /* Do not (really) need to teardown the display */
6607ec681f3Smrg         _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay");
6617ec681f3Smrg         return NULL;
6627ec681f3Smrg      }
6637ec681f3Smrg   }
6647ec681f3Smrg
6657ec681f3Smrg   return display;
66601e04c3fSmrg}
667