/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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.
*
* Each EGLDisplay has one or more screens (CRTs, Flat Panels, etc).
* The screens' handles can be obtained with eglGetScreensMESA().
*
* A new kind of EGLSurface is possible- one which can be directly scanned
* out on a screen. Such a surface is created with eglCreateScreenSurface().
*
* To actually display a screen surface on a screen, the eglShowSurface()
* function is called.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "egldisplay.h"
#include "eglcurrent.h"
#include "eglmode.h"
#include "eglsurface.h"
#include "eglscreen.h"
#include "eglmutex.h"
#ifdef EGL_MESA_screen_surface
/* ugh, no atomic op? */
static _EGL_DECLARE_MUTEX(_eglNextScreenHandleMutex);
static EGLScreenMESA _eglNextScreenHandle = 1;
/**
* Return a new screen handle/ID.
* NOTE: we never reuse these!
*/
static EGLScreenMESA
_eglAllocScreenHandle(void)
{
EGLScreenMESA s;
_eglLockMutex(&_eglNextScreenHandleMutex);
s = _eglNextScreenHandle;
_eglNextScreenHandle += _EGL_SCREEN_MAX_MODES;
_eglUnlockMutex(&_eglNextScreenHandleMutex);
return s;
}
/**
* Initialize an _EGLScreen object to default values.
*/
void
_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 = (_EGLMode *) calloc(num_modes, sizeof(*screen->Modes));
screen->NumModes = (screen->Modes) ? num_modes : 0;
}
/**
* Link a screen to its display and return the handle of the link.
* The handle can be passed to client directly.
*/
EGLScreenMESA
_eglLinkScreen(_EGLScreen *screen)
{
_EGLDisplay *display;
EGLint i;
assert(screen && screen->Display);
display = screen->Display;
if (!display->Screens) {
display->Screens = _eglCreateArray("Screen", 4);
if (!display->Screens)
return (EGLScreenMESA) 0;
}
screen->Handle = _eglAllocScreenHandle();
for (i = 0; i < screen->NumModes; i++)
screen->Modes[i].Handle = screen->Handle + i;
_eglAppendArray(display->Screens, (void *) screen);
return screen->Handle;
}
/**
* Lookup a handle to find the linked config.
* Return NULL if the handle has no corresponding linked config.
*/
_EGLScreen *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
{
EGLint i;
if (!display || !display->Screens)
return NULL;
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;
}
static EGLBoolean
_eglFlattenScreen(void *elem, void *buffer)
{
_EGLScreen *scr = (_EGLScreen *) elem;
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
*handle = _eglGetScreenHandle(scr);
return EGL_TRUE;
}
EGLBoolean
_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens,
EGLint max_screens, EGLint *num_screens)
{
*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,
_EGLScreen *scrn, EGLint x, EGLint y)
{
scrn->OriginX = x;
scrn->OriginY = y;
return EGL_TRUE;
}
/**
* Query a screen's current surface.
*/
EGLBoolean
_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
_EGLScreen *scrn, _EGLSurface **surf)
{
*surf = scrn->CurrentSurface;
return EGL_TRUE;
}
/**
* Query a screen's current mode.
*/
EGLBoolean
_eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
_EGLMode **m)
{
*m = scrn->CurrentMode;
return EGL_TRUE;
}
EGLBoolean
_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
EGLint attribute, EGLint *value)
{
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;
}
return EGL_TRUE;
}
#endif /* EGL_MESA_screen_surface */