egldisplay.c revision 3464ebd5
13464ebd5Sriastradh/**************************************************************************
23464ebd5Sriastradh *
33464ebd5Sriastradh * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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>
384a49301eSmrg#include "eglcontext.h"
394a49301eSmrg#include "eglsurface.h"
404a49301eSmrg#include "egldisplay.h"
414a49301eSmrg#include "egldriver.h"
424a49301eSmrg#include "eglglobals.h"
434a49301eSmrg#include "eglmutex.h"
444a49301eSmrg#include "egllog.h"
454a49301eSmrg
464a49301eSmrg
473464ebd5Sriastradh/**
483464ebd5Sriastradh * Return the native platform by parsing EGL_PLATFORM.
493464ebd5Sriastradh */
503464ebd5Sriastradhstatic _EGLPlatformType
513464ebd5Sriastradh_eglGetNativePlatformFromEnv(void)
523464ebd5Sriastradh{
533464ebd5Sriastradh   /* map --with-egl-platforms names to platform types */
543464ebd5Sriastradh   static const struct {
553464ebd5Sriastradh      _EGLPlatformType platform;
563464ebd5Sriastradh      const char *name;
573464ebd5Sriastradh   } egl_platforms[_EGL_NUM_PLATFORMS] = {
583464ebd5Sriastradh      { _EGL_PLATFORM_WINDOWS, "gdi" },
593464ebd5Sriastradh      { _EGL_PLATFORM_X11, "x11" },
603464ebd5Sriastradh      { _EGL_PLATFORM_WAYLAND, "wayland" },
613464ebd5Sriastradh      { _EGL_PLATFORM_DRM, "drm" },
623464ebd5Sriastradh      { _EGL_PLATFORM_FBDEV, "fbdev" }
633464ebd5Sriastradh   };
643464ebd5Sriastradh   _EGLPlatformType plat = _EGL_INVALID_PLATFORM;
653464ebd5Sriastradh   const char *plat_name;
663464ebd5Sriastradh   EGLint i;
673464ebd5Sriastradh
683464ebd5Sriastradh   plat_name = getenv("EGL_PLATFORM");
693464ebd5Sriastradh   /* try deprecated env variable */
703464ebd5Sriastradh   if (!plat_name || !plat_name[0])
713464ebd5Sriastradh      plat_name = getenv("EGL_DISPLAY");
723464ebd5Sriastradh   if (!plat_name || !plat_name[0])
733464ebd5Sriastradh      return _EGL_INVALID_PLATFORM;
743464ebd5Sriastradh
753464ebd5Sriastradh   for (i = 0; i < _EGL_NUM_PLATFORMS; i++) {
763464ebd5Sriastradh      if (strcmp(egl_platforms[i].name, plat_name) == 0) {
773464ebd5Sriastradh         plat = egl_platforms[i].platform;
783464ebd5Sriastradh         break;
793464ebd5Sriastradh      }
803464ebd5Sriastradh   }
813464ebd5Sriastradh
823464ebd5Sriastradh   return plat;
833464ebd5Sriastradh}
843464ebd5Sriastradh
853464ebd5Sriastradh
863464ebd5Sriastradh/**
873464ebd5Sriastradh * Return the native platform.  It is the platform of the EGL native types.
883464ebd5Sriastradh */
893464ebd5Sriastradh_EGLPlatformType
903464ebd5Sriastradh_eglGetNativePlatform(void)
913464ebd5Sriastradh{
923464ebd5Sriastradh   static _EGLPlatformType native_platform = _EGL_INVALID_PLATFORM;
933464ebd5Sriastradh
943464ebd5Sriastradh   if (native_platform == _EGL_INVALID_PLATFORM) {
953464ebd5Sriastradh      native_platform = _eglGetNativePlatformFromEnv();
963464ebd5Sriastradh      if (native_platform == _EGL_INVALID_PLATFORM)
973464ebd5Sriastradh         native_platform = _EGL_NATIVE_PLATFORM;
983464ebd5Sriastradh   }
993464ebd5Sriastradh
1003464ebd5Sriastradh   return native_platform;
1013464ebd5Sriastradh}
1023464ebd5Sriastradh
1033464ebd5Sriastradh
1044a49301eSmrg/**
1054a49301eSmrg * Finish display management.
1064a49301eSmrg */
1074a49301eSmrgvoid
1084a49301eSmrg_eglFiniDisplay(void)
1094a49301eSmrg{
1104a49301eSmrg   _EGLDisplay *dpyList, *dpy;
1114a49301eSmrg
1124a49301eSmrg   /* atexit function is called with global mutex locked */
1134a49301eSmrg   dpyList = _eglGlobal.DisplayList;
1144a49301eSmrg   while (dpyList) {
115cdc920a0Smrg      EGLint i;
116cdc920a0Smrg
1174a49301eSmrg      /* pop list head */
1184a49301eSmrg      dpy = dpyList;
1194a49301eSmrg      dpyList = dpyList->Next;
1204a49301eSmrg
121cdc920a0Smrg      for (i = 0; i < _EGL_NUM_RESOURCES; i++) {
122cdc920a0Smrg         if (dpy->ResourceLists[i]) {
123cdc920a0Smrg            _eglLog(_EGL_DEBUG, "Display %p is destroyed with resources", dpy);
124cdc920a0Smrg            break;
125cdc920a0Smrg         }
126cdc920a0Smrg      }
1274a49301eSmrg
1284a49301eSmrg      free(dpy);
1294a49301eSmrg   }
1304a49301eSmrg   _eglGlobal.DisplayList = NULL;
1314a49301eSmrg}
1324a49301eSmrg
1334a49301eSmrg
1344a49301eSmrg/**
135cdc920a0Smrg * Find the display corresponding to the specified native display, or create a
136cdc920a0Smrg * new one.
1374a49301eSmrg */
1384a49301eSmrg_EGLDisplay *
1393464ebd5Sriastradh_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy)
1404a49301eSmrg{
1414a49301eSmrg   _EGLDisplay *dpy;
1424a49301eSmrg
1433464ebd5Sriastradh   if (plat == _EGL_INVALID_PLATFORM)
1443464ebd5Sriastradh      return NULL;
1453464ebd5Sriastradh
1464a49301eSmrg   _eglLockMutex(_eglGlobal.Mutex);
1474a49301eSmrg
148cdc920a0Smrg   /* search the display list first */
1494a49301eSmrg   dpy = _eglGlobal.DisplayList;
1504a49301eSmrg   while (dpy) {
1513464ebd5Sriastradh      if (dpy->Platform == plat && dpy->PlatformDisplay == plat_dpy)
152cdc920a0Smrg         break;
1534a49301eSmrg      dpy = dpy->Next;
1544a49301eSmrg   }
1554a49301eSmrg
156cdc920a0Smrg   /* create a new display */
157cdc920a0Smrg   if (!dpy) {
158cdc920a0Smrg      dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay));
159cdc920a0Smrg      if (dpy) {
160cdc920a0Smrg         _eglInitMutex(&dpy->Mutex);
1613464ebd5Sriastradh         dpy->Platform = plat;
1623464ebd5Sriastradh         dpy->PlatformDisplay = plat_dpy;
163cdc920a0Smrg
164cdc920a0Smrg         /* add to the display list */
165cdc920a0Smrg         dpy->Next = _eglGlobal.DisplayList;
166cdc920a0Smrg         _eglGlobal.DisplayList = dpy;
167cdc920a0Smrg      }
168cdc920a0Smrg   }
169cdc920a0Smrg
1704a49301eSmrg   _eglUnlockMutex(_eglGlobal.Mutex);
1714a49301eSmrg
172cdc920a0Smrg   return dpy;
1734a49301eSmrg}
1744a49301eSmrg
1754a49301eSmrg
1764a49301eSmrg/**
1774a49301eSmrg * Destroy the contexts and surfaces that are linked to the display.
1784a49301eSmrg */
1794a49301eSmrgvoid
1804a49301eSmrg_eglReleaseDisplayResources(_EGLDriver *drv, _EGLDisplay *display)
1814a49301eSmrg{
182cdc920a0Smrg   _EGLResource *list;
1834a49301eSmrg
184cdc920a0Smrg   list = display->ResourceLists[_EGL_RESOURCE_CONTEXT];
185cdc920a0Smrg   while (list) {
186cdc920a0Smrg      _EGLContext *ctx = (_EGLContext *) list;
187cdc920a0Smrg      list = list->Next;
1884a49301eSmrg
1894a49301eSmrg      _eglUnlinkContext(ctx);
1904a49301eSmrg      drv->API.DestroyContext(drv, display, ctx);
1914a49301eSmrg   }
192cdc920a0Smrg   assert(!display->ResourceLists[_EGL_RESOURCE_CONTEXT]);
1934a49301eSmrg
194cdc920a0Smrg   list = display->ResourceLists[_EGL_RESOURCE_SURFACE];
195cdc920a0Smrg   while (list) {
196cdc920a0Smrg      _EGLSurface *surf = (_EGLSurface *) list;
197cdc920a0Smrg      list = list->Next;
1984a49301eSmrg
1994a49301eSmrg      _eglUnlinkSurface(surf);
2004a49301eSmrg      drv->API.DestroySurface(drv, display, surf);
2014a49301eSmrg   }
202cdc920a0Smrg   assert(!display->ResourceLists[_EGL_RESOURCE_SURFACE]);
2034a49301eSmrg}
2044a49301eSmrg
2054a49301eSmrg
2064a49301eSmrg/**
2074a49301eSmrg * Free all the data hanging of an _EGLDisplay object, but not
2084a49301eSmrg * the object itself.
2094a49301eSmrg */
2104a49301eSmrgvoid
2114a49301eSmrg_eglCleanupDisplay(_EGLDisplay *disp)
2124a49301eSmrg{
2134a49301eSmrg   if (disp->Configs) {
2143464ebd5Sriastradh      _eglDestroyArray(disp->Configs, free);
2154a49301eSmrg      disp->Configs = NULL;
2164a49301eSmrg   }
2174a49301eSmrg
2184a49301eSmrg   /* XXX incomplete */
2194a49301eSmrg}
2204a49301eSmrg
2214a49301eSmrg
2224a49301eSmrg/**
2234a49301eSmrg * Return EGL_TRUE if the given handle is a valid handle to a display.
2244a49301eSmrg */
2254a49301eSmrgEGLBoolean
2264a49301eSmrg_eglCheckDisplayHandle(EGLDisplay dpy)
2274a49301eSmrg{
2284a49301eSmrg   _EGLDisplay *cur;
2294a49301eSmrg
2304a49301eSmrg   _eglLockMutex(_eglGlobal.Mutex);
2314a49301eSmrg   cur = _eglGlobal.DisplayList;
2324a49301eSmrg   while (cur) {
2334a49301eSmrg      if (cur == (_EGLDisplay *) dpy)
2344a49301eSmrg         break;
2354a49301eSmrg      cur = cur->Next;
2364a49301eSmrg   }
2374a49301eSmrg   _eglUnlockMutex(_eglGlobal.Mutex);
2384a49301eSmrg   return (cur != NULL);
2394a49301eSmrg}
2404a49301eSmrg
2414a49301eSmrg
2424a49301eSmrg/**
243cdc920a0Smrg * Return EGL_TRUE if the given resource is valid.  That is, the display does
244cdc920a0Smrg * own the resource.
2454a49301eSmrg */
2464a49301eSmrgEGLBoolean
247cdc920a0Smrg_eglCheckResource(void *res, _EGLResourceType type, _EGLDisplay *dpy)
2484a49301eSmrg{
249cdc920a0Smrg   _EGLResource *list = dpy->ResourceLists[type];
250cdc920a0Smrg
251cdc920a0Smrg   if (!res)
252cdc920a0Smrg      return EGL_FALSE;
253cdc920a0Smrg
254cdc920a0Smrg   while (list) {
255cdc920a0Smrg      if (res == (void *) list) {
256cdc920a0Smrg         assert(list->Display == dpy);
2574a49301eSmrg         break;
2584a49301eSmrg      }
259cdc920a0Smrg      list = list->Next;
2604a49301eSmrg   }
261cdc920a0Smrg
262cdc920a0Smrg   return (list != NULL);
2634a49301eSmrg}
2644a49301eSmrg
2654a49301eSmrg
2664a49301eSmrg/**
2673464ebd5Sriastradh * Initialize a display resource.
2684a49301eSmrg */
269cdc920a0Smrgvoid
2703464ebd5Sriastradh_eglInitResource(_EGLResource *res, EGLint size, _EGLDisplay *dpy)
2714a49301eSmrg{
2723464ebd5Sriastradh   memset(res, 0, size);
273cdc920a0Smrg   res->Display = dpy;
2743464ebd5Sriastradh   res->RefCount = 1;
2753464ebd5Sriastradh}
2763464ebd5Sriastradh
2773464ebd5Sriastradh
2783464ebd5Sriastradh/**
2793464ebd5Sriastradh * Increment reference count for the resource.
2803464ebd5Sriastradh */
2813464ebd5Sriastradhvoid
2823464ebd5Sriastradh_eglGetResource(_EGLResource *res)
2833464ebd5Sriastradh{
2843464ebd5Sriastradh   assert(res && res->RefCount > 0);
2853464ebd5Sriastradh   /* hopefully a resource is always manipulated with its display locked */
2863464ebd5Sriastradh   res->RefCount++;
2873464ebd5Sriastradh}
2883464ebd5Sriastradh
2893464ebd5Sriastradh
2903464ebd5Sriastradh/**
2913464ebd5Sriastradh * Decrement reference count for the resource.
2923464ebd5Sriastradh */
2933464ebd5SriastradhEGLBoolean
2943464ebd5Sriastradh_eglPutResource(_EGLResource *res)
2953464ebd5Sriastradh{
2963464ebd5Sriastradh   assert(res && res->RefCount > 0);
2973464ebd5Sriastradh   res->RefCount--;
2983464ebd5Sriastradh   return (!res->RefCount);
2993464ebd5Sriastradh}
3003464ebd5Sriastradh
3013464ebd5Sriastradh
3023464ebd5Sriastradh/**
3033464ebd5Sriastradh * Link a resource to its display.
3043464ebd5Sriastradh */
3053464ebd5Sriastradhvoid
3063464ebd5Sriastradh_eglLinkResource(_EGLResource *res, _EGLResourceType type)
3073464ebd5Sriastradh{
3083464ebd5Sriastradh   assert(res->Display);
3093464ebd5Sriastradh
310cdc920a0Smrg   res->IsLinked = EGL_TRUE;
3113464ebd5Sriastradh   res->Next = res->Display->ResourceLists[type];
3123464ebd5Sriastradh   res->Display->ResourceLists[type] = res;
3133464ebd5Sriastradh   _eglGetResource(res);
3144a49301eSmrg}
3154a49301eSmrg
3164a49301eSmrg
317cdc920a0Smrg/**
318cdc920a0Smrg * Unlink a linked resource from its display.
319cdc920a0Smrg */
320cdc920a0Smrgvoid
321cdc920a0Smrg_eglUnlinkResource(_EGLResource *res, _EGLResourceType type)
322cdc920a0Smrg{
323cdc920a0Smrg   _EGLResource *prev;
324cdc920a0Smrg
325cdc920a0Smrg   prev = res->Display->ResourceLists[type];
326cdc920a0Smrg   if (prev != res) {
327cdc920a0Smrg      while (prev) {
328cdc920a0Smrg         if (prev->Next == res)
329cdc920a0Smrg            break;
330cdc920a0Smrg         prev = prev->Next;
331cdc920a0Smrg      }
332cdc920a0Smrg      assert(prev);
333cdc920a0Smrg      prev->Next = res->Next;
334cdc920a0Smrg   }
335cdc920a0Smrg   else {
336cdc920a0Smrg      res->Display->ResourceLists[type] = res->Next;
337cdc920a0Smrg   }
338cdc920a0Smrg
339cdc920a0Smrg   res->Next = NULL;
340cdc920a0Smrg   res->IsLinked = EGL_FALSE;
3413464ebd5Sriastradh   _eglPutResource(res);
3423464ebd5Sriastradh
3433464ebd5Sriastradh   /* We always unlink before destroy.  The driver still owns a reference */
3443464ebd5Sriastradh   assert(res->RefCount);
345cdc920a0Smrg}
346