eglscreen.c revision 08a482e7a9d13db5d4e6fd974942f6699d7d49dc
1/*
2 * Ideas for screen management extension to EGL.
3 *
4 * Each EGLDisplay has one or more screens (CRTs, Flat Panels, etc).
5 * The screens' handles can be obtained with eglGetScreensMESA().
6 *
7 * A new kind of EGLSurface is possible- one which can be directly scanned
8 * out on a screen.  Such a surface is created with eglCreateScreenSurface().
9 *
10 * To actually display a screen surface on a screen, the eglShowSurface()
11 * function is called.
12 */
13
14#include <assert.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include "egldisplay.h"
19#include "eglcurrent.h"
20#include "eglmode.h"
21#include "eglconfig.h"
22#include "eglsurface.h"
23#include "eglscreen.h"
24#include "eglmutex.h"
25
26
27#ifdef EGL_MESA_screen_surface
28
29
30/* ugh, no atomic op? */
31static _EGL_DECLARE_MUTEX(_eglNextScreenHandleMutex);
32static EGLScreenMESA _eglNextScreenHandle = 1;
33
34
35/**
36 * Return a new screen handle/ID.
37 * NOTE: we never reuse these!
38 */
39static EGLScreenMESA
40_eglAllocScreenHandle(void)
41{
42   EGLScreenMESA s;
43
44   _eglLockMutex(&_eglNextScreenHandleMutex);
45   s = _eglNextScreenHandle++;
46   _eglUnlockMutex(&_eglNextScreenHandleMutex);
47
48   return s;
49}
50
51
52/**
53 * Initialize an _EGLScreen object to default values.
54 */
55void
56_eglInitScreen(_EGLScreen *screen)
57{
58   memset(screen, 0, sizeof(_EGLScreen));
59   screen->StepX = 1;
60   screen->StepY = 1;
61}
62
63
64/**
65 * Given a public screen handle, return the internal _EGLScreen object.
66 */
67_EGLScreen *
68_eglLookupScreen(EGLScreenMESA screen, _EGLDisplay *display)
69{
70   EGLint i;
71
72   if (!display || !display->Screens)
73      return NULL;
74
75   for (i = 0; i < display->Screens->Size; i++) {
76      _EGLScreen *scr = (_EGLScreen *) display->Screens->Elements[i];
77      if (scr->Handle == screen)
78         return scr;
79   }
80   return NULL;
81}
82
83
84/**
85 * Add the given _EGLScreen to the display's list of screens.
86 */
87void
88_eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
89{
90   assert(display);
91   assert(screen);
92
93   if (!display->Screens) {
94      display->Screens = _eglCreateArray("Screen", 4);
95      if (!display->Screens)
96         return;
97   }
98   screen->Handle = _eglAllocScreenHandle();
99   _eglAppendArray(display->Screens, (void *) screen);
100}
101
102
103
104static EGLBoolean
105_eglFlattenScreen(void *elem, void *buffer)
106{
107   _EGLScreen *scr = (_EGLScreen *) elem;
108   EGLScreenMESA *handle = (EGLScreenMESA *) buffer;
109   *handle = scr->Handle;
110   return EGL_TRUE;
111}
112
113
114EGLBoolean
115_eglGetScreensMESA(_EGLDriver *drv, _EGLDisplay *display, EGLScreenMESA *screens,
116                   EGLint max_screens, EGLint *num_screens)
117{
118   *num_screens = _eglFlattenArray(display->Screens, (void *) screens,
119         sizeof(screens[0]), max_screens, _eglFlattenScreen);
120
121   return EGL_TRUE;
122}
123
124
125/**
126 * Drivers should do a proper implementation.
127 */
128_EGLSurface *
129_eglCreateScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
130                            const EGLint *attrib_list)
131{
132   return NULL;
133}
134
135
136/**
137 * Show the given surface on the named screen.
138 * If surface is EGL_NO_SURFACE, disable the screen's output.
139 *
140 * This is just a placeholder function; drivers will always override
141 * this with code that _really_ shows the surface.
142 */
143EGLBoolean
144_eglShowScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
145                          _EGLScreen *scrn, _EGLSurface *surf,
146                          _EGLMode *mode)
147{
148   if (!surf) {
149      scrn->CurrentSurface = NULL;
150   }
151   else {
152      if (surf->Type != EGL_SCREEN_BIT_MESA) {
153         _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
154         return EGL_FALSE;
155      }
156      if (surf->Width < mode->Width || surf->Height < mode->Height) {
157         _eglError(EGL_BAD_SURFACE,
158                   "eglShowSurfaceMESA(surface smaller than screen size)");
159         return EGL_FALSE;
160      }
161
162      scrn->CurrentSurface = surf;
163      scrn->CurrentMode = mode;
164   }
165   return EGL_TRUE;
166}
167
168
169/**
170 * Set a screen's current display mode.
171 * Note: mode = EGL_NO_MODE is valid (turns off the screen)
172 *
173 * This is just a placeholder function; drivers will always override
174 * this with code that _really_ sets the mode.
175 */
176EGLBoolean
177_eglScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
178                   _EGLMode *m)
179{
180   scrn->CurrentMode = m;
181   return EGL_TRUE;
182}
183
184
185/**
186 * Set a screen's surface origin.
187 */
188EGLBoolean
189_eglScreenPositionMESA(_EGLDriver *drv, _EGLDisplay *dpy,
190                       _EGLScreen *scrn, EGLint x, EGLint y)
191{
192   scrn->OriginX = x;
193   scrn->OriginY = y;
194
195   return EGL_TRUE;
196}
197
198
199/**
200 * Query a screen's current surface.
201 */
202EGLBoolean
203_eglQueryScreenSurfaceMESA(_EGLDriver *drv, _EGLDisplay *dpy,
204                           _EGLScreen *scrn, _EGLSurface **surf)
205{
206   *surf = scrn->CurrentSurface;
207   return EGL_TRUE;
208}
209
210
211/**
212 * Query a screen's current mode.
213 */
214EGLBoolean
215_eglQueryScreenModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
216                        _EGLMode **m)
217{
218   *m = scrn->CurrentMode;
219   return EGL_TRUE;
220}
221
222
223EGLBoolean
224_eglQueryScreenMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
225                    EGLint attribute, EGLint *value)
226{
227   switch (attribute) {
228   case EGL_SCREEN_POSITION_MESA:
229      value[0] = scrn->OriginX;
230      value[1] = scrn->OriginY;
231      break;
232   case EGL_SCREEN_POSITION_GRANULARITY_MESA:
233      value[0] = scrn->StepX;
234      value[1] = scrn->StepY;
235      break;
236   default:
237      _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
238      return EGL_FALSE;
239   }
240
241   return EGL_TRUE;
242}
243
244
245/**
246 * Delete the modes associated with given screen.
247 */
248void
249_eglDestroyScreenModes(_EGLScreen *scrn)
250{
251   EGLint i;
252   for (i = 0; i < scrn->NumModes; i++) {
253      if (scrn->Modes[i].Name)
254         free((char *) scrn->Modes[i].Name); /* cast away const */
255   }
256   if (scrn->Modes)
257      free(scrn->Modes);
258   scrn->Modes = NULL;
259   scrn->NumModes = 0;
260}
261
262
263/**
264 * Default fallback routine - drivers should usually override this.
265 */
266void
267_eglDestroyScreen(_EGLScreen *scrn)
268{
269   _eglDestroyScreenModes(scrn);
270   free(scrn);
271}
272
273
274#endif /* EGL_MESA_screen_surface */
275