blob: 8f96fd935c7a8a9ea74a85c9e96fea802df61b76 [file] [log] [blame]
/*
* 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 "eglglobals.h"
#include "eglcurrent.h"
#include "eglmode.h"
#include "eglconfig.h"
#include "eglsurface.h"
#include "eglscreen.h"
#include "eglmutex.h"
/**
* Return a new screen handle/ID.
* NOTE: we never reuse these!
*/
static EGLScreenMESA
_eglAllocScreenHandle(void)
{
EGLScreenMESA s;
_eglLockMutex(_eglGlobal.Mutex);
s = _eglGlobal.FreeScreenHandle++;
_eglUnlockMutex(_eglGlobal.Mutex);
return s;
}
/**
* Initialize an _EGLScreen object to default values.
*/
void
_eglInitScreen(_EGLScreen *screen)
{
memset(screen, 0, sizeof(_EGLScreen));
screen->StepX = 1;
screen->StepY = 1;
}
/**
* Given a public screen handle, return the internal _EGLScreen object.
*/
_EGLScreen *
_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
{
EGLint i;
if (!display->Screens)
return NULL;
for (i = 0; i < display->Screens->Size; i++) {
_EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
if (scr->Handle == screen)
return scr;
}
return NULL;
}
/**
* Add the given _EGLScreen to the display's list of screens.
*/
void
_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
{
assert(display);
assert(screen);
if (!display->Screens) {
display->Screens = _eglCreateArray("Screen", 4);
if (!display->Screens)
return;
}
screen->Handle = _eglAllocScreenHandle();
_eglAppendArray(display->Screens, (void *) screen);
}
static EGLBoolean
_eglFlattenScreen(void *elem, void *buffer)
{
_EGLScreen *scr = (_EGLScreen *) elem;
EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
*handle = scr->Handle;
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;
}
/**
* Drivers should do a proper implementation.
*/
_EGLSurface *
_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
const EGLint *attrib_list)
{
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,
_EGLScreen *scrn, _EGLSurface *surf,
_EGLMode *mode)
{
if (!surf) {
scrn->CurrentSurface = NULL;
}
else {
if (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;
}
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, _EGLScreen *scrn,
_EGLMode *m)
{
scrn->CurrentMode = m;
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;
}
/**
* 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);
}