+/**************************************************************************
+ *
+ * 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;
}
* 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;
* 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;
}
* 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;
}
-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 */