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