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