egl: don't fill client apis string forever.
[mesa.git] / src / egl / main / eglscreen.c
index b6bde65e8b52a80c8611c8478a54b55775bb90a2..42ac621fcd98d5f3602d96c7414140413200c084 100644 (file)
@@ -1,3 +1,33 @@
+/**************************************************************************
+ *
+ * Copyright 2008 VMware, Inc.
+ * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
+ * Copyright 2010 LunarG, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
 /*
  * Ideas for screen management extension to EGL.
  *
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include "c11/threads.h"
 
 #include "egldisplay.h"
-#include "eglglobals.h"
+#include "eglcurrent.h"
 #include "eglmode.h"
-#include "eglconfig.h"
 #include "eglsurface.h"
 #include "eglscreen.h"
 
 
+#ifdef EGL_MESA_screen_surface
+
+
+/* ugh, no atomic op? */
+static mtx_t _eglNextScreenHandleMutex = _MTX_INITIALIZER_NP;
+static EGLScreenMESA _eglNextScreenHandle = 1;
+
+
 /**
  * Return a new screen handle/ID.
  * NOTE: we never reuse these!
  */
-EGLScreenMESA
+static EGLScreenMESA
 _eglAllocScreenHandle(void)
 {
-   EGLScreenMESA s = _eglGlobal.FreeScreenHandle;
-   _eglGlobal.FreeScreenHandle++;
+   EGLScreenMESA s;
+
+   mtx_lock(&_eglNextScreenHandleMutex);
+   s = _eglNextScreenHandle;
+   _eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
+   mtx_unlock(&_eglNextScreenHandleMutex);
+
    return s;
 }
 
@@ -40,183 +83,90 @@ _eglAllocScreenHandle(void)
  * Initialize an _EGLScreen object to default values.
  */
 void
-_eglInitScreen(_EGLScreen *screen)
+_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
 {
    memset(screen, 0, sizeof(_EGLScreen));
+
+   screen->Display = dpy;
+   screen->NumModes = num_modes;
    screen->StepX = 1;
    screen->StepY = 1;
+
+   if (num_modes > _EGL_SCREEN_MAX_MODES)
+      num_modes = _EGL_SCREEN_MAX_MODES;
+   screen->Modes = calloc(num_modes, sizeof(*screen->Modes));
+   screen->NumModes = (screen->Modes) ? num_modes : 0;
 }
 
 
 /**
- * Given a public screen handle, return the internal _EGLScreen object.
+ * Link a screen to its display and return the handle of the link.
+ * The handle can be passed to client directly.
  */
-_EGLScreen *
-_eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen)
+EGLScreenMESA
+_eglLinkScreen(_EGLScreen *screen)
 {
+   _EGLDisplay *display;
    EGLint i;
-   _EGLDisplay *display = _eglLookupDisplay(dpy);
 
-   if (!display)
-      return NULL;
+   assert(screen && screen->Display);
+   display = screen->Display;
 
-   for (i = 0; i < display->NumScreens; i++) {
-      if (display->Screens[i]->Handle == screen)
-         return display->Screens[i];
+   if (!display->Screens) {
+      display->Screens = _eglCreateArray("Screen", 4);
+      if (!display->Screens)
+         return (EGLScreenMESA) 0;
    }
-   return NULL;
-}
-
-
-/**
- * Add the given _EGLScreen to the display's list of screens.
- */
-void
-_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
-{
-   EGLint n;
-
-   assert(display);
-   assert(screen);
 
    screen->Handle = _eglAllocScreenHandle();
-   n = display->NumScreens;
-   display->Screens = realloc(display->Screens, (n+1) * sizeof(_EGLScreen *));
-   display->Screens[n] = screen;
-   display->NumScreens++;
-}
-
+   for (i = 0; i < screen->NumModes; i++)
+      screen->Modes[i].Handle = screen->Handle + i;
 
+   _eglAppendArray(display->Screens, (void *) screen);
 
-EGLBoolean
-_eglGetScreensMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens,
-                   EGLint max_screens, EGLint *num_screens)
-{
-   _EGLDisplay *display = _eglLookupDisplay(dpy);
-   EGLint n;
-
-   if (!display) {
-      _eglError(EGL_BAD_DISPLAY, "eglGetScreensMESA");
-      return EGL_FALSE;
-   }
-
-   if (display->NumScreens > max_screens) {
-      n = max_screens;
-   }
-   else {
-      n = display->NumScreens;
-   }
-
-   if (screens) {
-      EGLint i;
-      for (i = 0; i < n; i++)
-         screens[i] = display->Screens[i]->Handle;
-   }
-   if (num_screens)
-      *num_screens = n;
-
-   return EGL_TRUE;
+   return screen->Handle;
 }
 
 
 /**
- * Example function - drivers should do a proper implementation.
+ * Lookup a handle to find the linked config.
+ * Return NULL if the handle has no corresponding linked config.
  */
-EGLSurface
-_eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
-                            const EGLint *attrib_list)
+_EGLScreen *
+_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
 {
-#if 0 /* THIS IS JUST EXAMPLE CODE */
-   _EGLSurface *surf;
-   _EGLConfig *conf;
-
-   conf = _eglLookupConfig(drv, dpy, config);
-   if (!conf) {
-      _eglError(EGL_BAD_CONFIG, "eglCreateScreenSurfaceMESA");
-      return EGL_NO_SURFACE;
-   }
+   EGLint i;
 
-   surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface));
-   if (!surf)
-      return EGL_NO_SURFACE;
+   if (!display || !display->Screens)
+      return NULL;
 
-   if (!_eglInitSurface(drv, surf, EGL_SCREEN_BIT_MESA,
-                        conf, attrib_list)) {
-      free(surf);
-      return EGL_NO_SURFACE;
+   for (i = 0; i < display->Screens->Size; i++) {
+      _EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
+      if (scr->Handle == screen) {
+         assert(scr->Display == display);
+         return scr;
+      }
    }
-
-   return _eglLinkSurface(surf, _eglLookupDisplay(dpy));
-#endif
-   return EGL_NO_SURFACE;
+   return NULL;
 }
 
 
-/**
- * Show the given surface on the named screen.
- * If surface is EGL_NO_SURFACE, disable the screen's output.
- * 
- * This is just a placeholder function; drivers will always override
- * this with code that _really_ shows the surface.
- */
-EGLBoolean
-_eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
-                          EGLScreenMESA screen, EGLSurface surface,
-                          EGLModeMESA m)
+static EGLBoolean
+_eglFlattenScreen(void *elem, void *buffer)
 {
-   _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-   _EGLMode *mode = _eglLookupMode(dpy, m);
-
-   if (!scrn) {
-      _eglError(EGL_BAD_SCREEN_MESA, "eglShowSurfaceMESA");
-      return EGL_FALSE;
-   }
-   if (!mode && (m != EGL_NO_MODE_MESA )) {
-      _eglError(EGL_BAD_MODE_MESA, "eglShowSurfaceMESA");
-      return EGL_FALSE;
-   }
-
-   if (surface == EGL_NO_SURFACE) {
-      scrn->CurrentSurface = NULL;
-   }
-   else {
-      _EGLSurface *surf = _eglLookupSurface(surface);
-      if (!surf || surf->Type != EGL_SCREEN_BIT_MESA) {
-         _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
-         return EGL_FALSE;
-      }
-      if (surf->Width < mode->Width || surf->Height < mode->Height) {
-         _eglError(EGL_BAD_SURFACE,
-                   "eglShowSurfaceMESA(surface smaller than screen size)");
-         return EGL_FALSE;
-      }
-
-      scrn->CurrentSurface = surf;
-      scrn->CurrentMode = mode;
-   }
+   _EGLScreen *scr = (_EGLScreen *) elem;
+   EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
+   *handle = _eglGetScreenHandle(scr);
    return EGL_TRUE;
 }
 
 
-/**
- * Set a screen's current display mode.
- * Note: mode = EGL_NO_MODE is valid (turns off the screen)
- *
- * This is just a placeholder function; drivers will always override
- * this with code that _really_ sets the mode.
- */
 EGLBoolean
-_eglScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
-                   EGLModeMESA mode)
+_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens,
+                   EGLint max_screens, EGLint *num_screens)
 {
-   _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-
-   if (!scrn) {
-      _eglError(EGL_BAD_SCREEN_MESA, "eglScreenModeMESA");
-      return EGL_FALSE;
-   }
-
-   scrn->CurrentMode = _eglLookupMode(dpy, mode);
+   *num_screens = _eglFlattenArray(display->Screens, (void *) screens,
+         sizeof(screens[0]), max_screens, _eglFlattenScreen);
 
    return EGL_TRUE;
 }
@@ -226,15 +176,9 @@ _eglScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
  * Set a screen's surface origin.
  */
 EGLBoolean
-_eglScreenPositionMESA(_EGLDriver *drv, EGLDisplay dpy,
-                       EGLScreenMESA screen, EGLint x, EGLint y)
+_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy,
+                       _EGLScreen *scrn, EGLint x, EGLint y)
 {
-   _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-   if (!scrn) {
-      _eglError(EGL_BAD_SCREEN_MESA, "eglScreenPositionMESA");
-      return EGL_FALSE;
-   }
-
    scrn->OriginX = x;
    scrn->OriginY = y;
 
@@ -246,14 +190,10 @@ _eglScreenPositionMESA(_EGLDriver *drv, EGLDisplay dpy,
  * Query a screen's current surface.
  */
 EGLBoolean
-_eglQueryScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
-                           EGLScreenMESA screen, EGLSurface *surface)
+_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
+                           _EGLScreen *scrn, _EGLSurface **surf)
 {
-   const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-   if (scrn->CurrentSurface)
-      *surface = scrn->CurrentSurface->Handle;
-   else
-      *surface = EGL_NO_SURFACE;
+   *surf = scrn->CurrentSurface;
    return EGL_TRUE;
 }
 
@@ -262,29 +202,18 @@ _eglQueryScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
  * Query a screen's current mode.
  */
 EGLBoolean
-_eglQueryScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
-                        EGLModeMESA *mode)
+_eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
+                        _EGLMode **m)
 {
-   const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-   if (scrn->CurrentMode)
-      *mode = scrn->CurrentMode->Handle;
-   else
-      *mode = EGL_NO_MODE_MESA;
+   *m = scrn->CurrentMode;
    return EGL_TRUE;
 }
 
 
 EGLBoolean
-_eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
                     EGLint attribute, EGLint *value)
 {
-   const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-
-   if (!scrn) {
-      _eglError(EGL_BAD_SCREEN_MESA, "eglQueryScreenMESA");
-      return EGL_FALSE;
-   }
-
    switch (attribute) {
    case EGL_SCREEN_POSITION_MESA:
       value[0] = scrn->OriginX;
@@ -303,31 +232,4 @@ _eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
 }
 
 
-/**
- * Delete the modes associated with given screen.
- */
-void
-_eglDestroyScreenModes(_EGLScreen *scrn)
-{
-   EGLint i;
-   for (i = 0; i < scrn->NumModes; i++) {
-      if (scrn->Modes[i].Name)
-         free((char *) scrn->Modes[i].Name); /* cast away const */
-   }
-   if (scrn->Modes)
-      free(scrn->Modes);
-   scrn->Modes = NULL;
-   scrn->NumModes = 0;
-}
-
-      
-/**
- * Default fallback routine - drivers should usually override this.
- */
-void
-_eglDestroyScreen(_EGLScreen *scrn)
-{
-   _eglDestroyScreenModes(scrn);
-   free(scrn);
-}
-
+#endif /* EGL_MESA_screen_surface */