Merge branch 'mesa_7_5_branch'
[mesa.git] / src / egl / main / eglscreen.c
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 "eglglobals.h"
20 #include "eglmode.h"
21 #include "eglconfig.h"
22 #include "eglsurface.h"
23 #include "eglscreen.h"
24
25
26 /**
27 * Return a new screen handle/ID.
28 * NOTE: we never reuse these!
29 */
30 EGLScreenMESA
31 _eglAllocScreenHandle(void)
32 {
33 EGLScreenMESA s = _eglGlobal.FreeScreenHandle;
34 _eglGlobal.FreeScreenHandle++;
35 return s;
36 }
37
38
39 /**
40 * Initialize an _EGLScreen object to default values.
41 */
42 void
43 _eglInitScreen(_EGLScreen *screen)
44 {
45 memset(screen, 0, sizeof(_EGLScreen));
46 screen->StepX = 1;
47 screen->StepY = 1;
48 }
49
50
51 /**
52 * Given a public screen handle, return the internal _EGLScreen object.
53 */
54 _EGLScreen *
55 _eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen)
56 {
57 EGLint i;
58 _EGLDisplay *display = _eglLookupDisplay(dpy);
59
60 if (!display)
61 return NULL;
62
63 for (i = 0; i < display->NumScreens; i++) {
64 if (display->Screens[i]->Handle == screen)
65 return display->Screens[i];
66 }
67 return NULL;
68 }
69
70
71 /**
72 * Add the given _EGLScreen to the display's list of screens.
73 */
74 void
75 _eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
76 {
77 EGLint n;
78
79 assert(display);
80 assert(screen);
81
82 screen->Handle = _eglAllocScreenHandle();
83 n = display->NumScreens;
84 display->Screens = realloc(display->Screens, (n+1) * sizeof(_EGLScreen *));
85 display->Screens[n] = screen;
86 display->NumScreens++;
87 }
88
89
90
91 EGLBoolean
92 _eglGetScreensMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens,
93 EGLint max_screens, EGLint *num_screens)
94 {
95 _EGLDisplay *display = _eglLookupDisplay(dpy);
96 EGLint n;
97
98 if (!display) {
99 _eglError(EGL_BAD_DISPLAY, "eglGetScreensMESA");
100 return EGL_FALSE;
101 }
102
103 if (display->NumScreens > max_screens) {
104 n = max_screens;
105 }
106 else {
107 n = display->NumScreens;
108 }
109
110 if (screens) {
111 EGLint i;
112 for (i = 0; i < n; i++)
113 screens[i] = display->Screens[i]->Handle;
114 }
115 if (num_screens)
116 *num_screens = n;
117
118 return EGL_TRUE;
119 }
120
121
122 /**
123 * Example function - drivers should do a proper implementation.
124 */
125 EGLSurface
126 _eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
127 const EGLint *attrib_list)
128 {
129 #if 0 /* THIS IS JUST EXAMPLE CODE */
130 _EGLSurface *surf;
131 _EGLConfig *conf;
132
133 conf = _eglLookupConfig(drv, dpy, config);
134 if (!conf) {
135 _eglError(EGL_BAD_CONFIG, "eglCreateScreenSurfaceMESA");
136 return EGL_NO_SURFACE;
137 }
138
139 surf = (_EGLSurface *) calloc(1, sizeof(_EGLSurface));
140 if (!surf)
141 return EGL_NO_SURFACE;
142
143 if (!_eglInitSurface(drv, surf, EGL_SCREEN_BIT_MESA,
144 conf, attrib_list)) {
145 free(surf);
146 return EGL_NO_SURFACE;
147 }
148
149 return _eglLinkSurface(surf, _eglLookupDisplay(dpy));
150 #endif
151 return EGL_NO_SURFACE;
152 }
153
154
155 /**
156 * Show the given surface on the named screen.
157 * If surface is EGL_NO_SURFACE, disable the screen's output.
158 *
159 * This is just a placeholder function; drivers will always override
160 * this with code that _really_ shows the surface.
161 */
162 EGLBoolean
163 _eglShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
164 EGLScreenMESA screen, EGLSurface surface,
165 EGLModeMESA m)
166 {
167 _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
168 _EGLMode *mode = _eglLookupMode(dpy, m);
169
170 if (!scrn) {
171 _eglError(EGL_BAD_SCREEN_MESA, "eglShowSurfaceMESA");
172 return EGL_FALSE;
173 }
174 if (!mode && (m != EGL_NO_MODE_MESA )) {
175 _eglError(EGL_BAD_MODE_MESA, "eglShowSurfaceMESA");
176 return EGL_FALSE;
177 }
178
179 if (surface == EGL_NO_SURFACE) {
180 scrn->CurrentSurface = NULL;
181 }
182 else {
183 _EGLSurface *surf = _eglLookupSurface(surface);
184 if (!surf || surf->Type != EGL_SCREEN_BIT_MESA) {
185 _eglError(EGL_BAD_SURFACE, "eglShowSurfaceMESA");
186 return EGL_FALSE;
187 }
188 if (surf->Width < mode->Width || surf->Height < mode->Height) {
189 _eglError(EGL_BAD_SURFACE,
190 "eglShowSurfaceMESA(surface smaller than screen size)");
191 return EGL_FALSE;
192 }
193
194 scrn->CurrentSurface = surf;
195 scrn->CurrentMode = mode;
196 }
197 return EGL_TRUE;
198 }
199
200
201 /**
202 * Set a screen's current display mode.
203 * Note: mode = EGL_NO_MODE is valid (turns off the screen)
204 *
205 * This is just a placeholder function; drivers will always override
206 * this with code that _really_ sets the mode.
207 */
208 EGLBoolean
209 _eglScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
210 EGLModeMESA mode)
211 {
212 _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
213
214 if (!scrn) {
215 _eglError(EGL_BAD_SCREEN_MESA, "eglScreenModeMESA");
216 return EGL_FALSE;
217 }
218
219 scrn->CurrentMode = _eglLookupMode(dpy, mode);
220
221 return EGL_TRUE;
222 }
223
224
225 /**
226 * Set a screen's surface origin.
227 */
228 EGLBoolean
229 _eglScreenPositionMESA(_EGLDriver *drv, EGLDisplay dpy,
230 EGLScreenMESA screen, EGLint x, EGLint y)
231 {
232 _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
233 if (!scrn) {
234 _eglError(EGL_BAD_SCREEN_MESA, "eglScreenPositionMESA");
235 return EGL_FALSE;
236 }
237
238 scrn->OriginX = x;
239 scrn->OriginY = y;
240
241 return EGL_TRUE;
242 }
243
244
245 /**
246 * Query a screen's current surface.
247 */
248 EGLBoolean
249 _eglQueryScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy,
250 EGLScreenMESA screen, EGLSurface *surface)
251 {
252 const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
253 if (scrn->CurrentSurface)
254 *surface = scrn->CurrentSurface->Handle;
255 else
256 *surface = EGL_NO_SURFACE;
257 return EGL_TRUE;
258 }
259
260
261 /**
262 * Query a screen's current mode.
263 */
264 EGLBoolean
265 _eglQueryScreenModeMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
266 EGLModeMESA *mode)
267 {
268 const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
269 if (scrn->CurrentMode)
270 *mode = scrn->CurrentMode->Handle;
271 else
272 *mode = EGL_NO_MODE_MESA;
273 return EGL_TRUE;
274 }
275
276
277 EGLBoolean
278 _eglQueryScreenMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
279 EGLint attribute, EGLint *value)
280 {
281 const _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
282
283 if (!scrn) {
284 _eglError(EGL_BAD_SCREEN_MESA, "eglQueryScreenMESA");
285 return EGL_FALSE;
286 }
287
288 switch (attribute) {
289 case EGL_SCREEN_POSITION_MESA:
290 value[0] = scrn->OriginX;
291 value[1] = scrn->OriginY;
292 break;
293 case EGL_SCREEN_POSITION_GRANULARITY_MESA:
294 value[0] = scrn->StepX;
295 value[1] = scrn->StepY;
296 break;
297 default:
298 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
299 return EGL_FALSE;
300 }
301
302 return EGL_TRUE;
303 }
304
305
306 /**
307 * Delete the modes associated with given screen.
308 */
309 void
310 _eglDestroyScreenModes(_EGLScreen *scrn)
311 {
312 EGLint i;
313 for (i = 0; i < scrn->NumModes; i++) {
314 if (scrn->Modes[i].Name)
315 free((char *) scrn->Modes[i].Name); /* cast away const */
316 }
317 if (scrn->Modes)
318 free(scrn->Modes);
319 scrn->Modes = NULL;
320 scrn->NumModes = 0;
321 }
322
323
324 /**
325 * Default fallback routine - drivers should usually override this.
326 */
327 void
328 _eglDestroyScreen(_EGLScreen *scrn)
329 {
330 _eglDestroyScreenModes(scrn);
331 free(scrn);
332 }
333