egl: don't fill client apis string forever.
[mesa.git] / src / egl / main / eglscreen.c
index 9669a22c07e7bd6503ba803372398e5fd559f811..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"
 
 
-/**
- * Initialize an _EGLScreen object to default values.
- */
-void
-_eglInitScreen(_EGLScreen *screen)
-{
-   /* just init to zero for now */
-   memset(screen, 0, sizeof(_EGLScreen));
-}
+#ifdef EGL_MESA_screen_surface
+
+
+/* ugh, no atomic op? */
+static mtx_t _eglNextScreenHandleMutex = _MTX_INITIALIZER_NP;
+static EGLScreenMESA _eglNextScreenHandle = 1;
 
 
 /**
- * Given a public screen handle, return the internal _EGLScreen object.
+ * Return a new screen handle/ID.
+ * NOTE: we never reuse these!
  */
-_EGLScreen *
-_eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen)
+static EGLScreenMESA
+_eglAllocScreenHandle(void)
 {
-   EGLint i;
-   _EGLDisplay *display = _eglLookupDisplay(dpy);
+   EGLScreenMESA s;
 
-   if (!display)
-      return NULL;
+   mtx_lock(&_eglNextScreenHandleMutex);
+   s = _eglNextScreenHandle;
+   _eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
+   mtx_unlock(&_eglNextScreenHandleMutex);
 
-   for (i = 0; i < display->NumScreens; i++) {
-      if (display->Screens[i]->Handle == screen)
-         return display->Screens[i];
-   }
-   return NULL;
+   return s;
 }
 
 
 /**
- * Add the given _EGLScreen to the display's list of screens.
+ * Initialize an _EGLScreen object to default values.
  */
 void
-_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
+_eglInitScreen(_EGLScreen *screen, _EGLDisplay *dpy, EGLint num_modes)
 {
-   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++;
-}
-
-
-
-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;
-   }
+   memset(screen, 0, sizeof(_EGLScreen));
 
-   if (screens) {
-      EGLint i;
-      for (i = 0; i < n; i++)
-         screens[i] = display->Screens[i]->Handle;
-   }
-   if (num_screens)
-      *num_screens = n;
+   screen->Display = dpy;
+   screen->NumModes = num_modes;
+   screen->StepX = 1;
+   screen->StepY = 1;
 
-   return EGL_TRUE;
+   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;
 }
 
 
 /**
- * Initialize the given _EGLSurface object.  Assign it an EGLSurface handle.
- * Return the EGLSurface handle or EGL_BAD_SURFACE if error.
+ * Link a screen to its display and return the handle of the link.
+ * The handle can be passed to client directly.
  */
-EGLSurface
-_eglInitScreenSurface(_EGLSurface *surf, _EGLDriver *drv, EGLDisplay dpy,
-                      EGLConfig config, const EGLint *attrib_list)
+EGLScreenMESA
+_eglLinkScreen(_EGLScreen *screen)
 {
-   EGLint width = 0, height = 0;
+   _EGLDisplay *display;
    EGLint i;
 
-   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
-      switch (attrib_list[i]) {
-      case EGL_WIDTH:
-         width = attrib_list[++i];
-         break;
-      case EGL_HEIGHT:
-         height = attrib_list[++i];
-         break;
-      default:
-         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateScreenSurfaceMESA");
-         return EGL_NO_SURFACE;
-      }
-   }
+   assert(screen && screen->Display);
+   display = screen->Display;
 
-   if (width <= 0 || height <= 0) {
-      _eglError(EGL_BAD_ATTRIBUTE,
-                "eglCreateScreenSurfaceMESA(width or height)");
-      return EGL_NO_SURFACE;
+   if (!display->Screens) {
+      display->Screens = _eglCreateArray("Screen", 4);
+      if (!display->Screens)
+         return (EGLScreenMESA) 0;
    }
 
-   _eglInitSurface(surf);
-   surf->Width = width;
-   surf->Height = height;
-   surf->Type = EGL_SCREEN_BIT_MESA;
-   surf->Config =  _eglLookupConfig(drv, dpy, config);
+   screen->Handle = _eglAllocScreenHandle();
+   for (i = 0; i < screen->NumModes; i++)
+      screen->Modes[i].Handle = screen->Handle + i;
 
-   /* insert into hash table */
-   _eglSaveSurface(surf);
-   assert(surf->Handle);
+   _eglAppendArray(display->Screens, (void *) screen);
 
-   return surf->Handle;
+   return screen->Handle;
 }
 
 
 /**
- * Create a drawing surface which can be directly displayed on a screen.
+ * 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)
 {
-   _EGLSurface *surf;
-   EGLSurface surface;
-   
-   surf = (_EGLSurface *) malloc(sizeof(_EGLSurface));
-   surface = _eglInitScreenSurface(surf, drv, dpy, config, attrib_list);
-   if (surface == EGL_NO_SURFACE)
-      free(surf);
-
-   return surface;
-}
-
+   EGLint i;
 
-/**
- * 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
-_eglShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
-                    EGLSurface surface, EGLModeMESA m)
-{
-   _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
-   _EGLMode *mode = _eglLookupMode(dpy, m);
+   if (!display || !display->Screens)
+      return NULL;
 
-   if (!scrn) {
-      _eglError(EGL_BAD_SCREEN_MESA, "eglShowSurfaceMESA");
-      return EGL_FALSE;
-   }
-   if (!mode) {
-      _eglError(EGL_BAD_MODE_MESA, "eglShowSurfaceMESA");
-      return EGL_FALSE;
+   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 NULL;
+}
 
-   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;
-   }
+static EGLBoolean
+_eglFlattenScreen(void *elem, void *buffer)
+{
+   _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;
 }
@@ -241,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;
 
@@ -261,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;
 }
 
@@ -277,34 +202,27 @@ _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;
       value[1] = scrn->OriginY;
       break;
+   case EGL_SCREEN_POSITION_GRANULARITY_MESA:
+      value[0] = scrn->StepX;
+      value[1] = scrn->StepY;
+      break;
    default:
       _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
       return EGL_FALSE;
@@ -314,20 +232,4 @@ _eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
 }
 
 
-void
-_eglDestroyScreenModes(_EGLScreen *scrn)
-{
-   free(scrn->Modes);
-}
-
-      
-/**
- * Default fallback routine - drivers should usually override this.
- */
-void
-_eglDestroyScreen(_EGLScreen *scrn)
-{
-   _eglDestroyScreenModes(scrn);
-   free(scrn);
-}
-
+#endif /* EGL_MESA_screen_surface */