sync with latest EGL_MESA_screen_surface spec (EGLScreenMESA handles)
[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 "egldisplay.h"
17 #include "eglglobals.h"
18 #include "eglmode.h"
19 #include "eglsurface.h"
20 #include "eglscreen.h"
21
22
23 /**
24 * Return a new _EGLScreen object.
25 */
26 _EGLScreen *
27 _eglNewScreen(void)
28 {
29 return (_EGLScreen *) calloc(1, sizeof(_EGLScreen));
30 }
31
32
33 /**
34 * Given a public screen handle, return the internal _EGLScreen object.
35 */
36 _EGLScreen *
37 _eglLookupScreen(EGLDisplay dpy, EGLScreenMESA screen)
38 {
39 EGLint i;
40 _EGLDisplay *display = _eglLookupDisplay(dpy);
41
42 if (!display)
43 return NULL;
44
45 for (i = 0; i < display->NumScreens; i++) {
46 if (display->Screens[i]->Handle == screen)
47 return display->Screens[i];
48 }
49 return NULL;
50 }
51
52
53 /**
54 * Add the given _EGLScreen to the display's list of screens.
55 */
56 void
57 _eglAddScreen(_EGLDisplay *display, _EGLScreen *screen)
58 {
59 EGLint n;
60
61 assert(display);
62 assert(screen);
63
64 screen->Handle = _eglAllocScreenHandle();
65 n = display->NumScreens;
66 display->Screens = realloc(display->Screens, (n+1) * sizeof(_EGLScreen *));
67 display->Screens[n] = screen;
68 display->NumScreens++;
69 }
70
71
72
73 EGLBoolean
74 _eglGetScreensMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA *screens,
75 EGLint max_screens, EGLint *num_screens)
76 {
77 _EGLDisplay *display = _eglLookupDisplay(dpy);
78 EGLint n;
79
80 if (!display) {
81 _eglError(EGL_BAD_DISPLAY, "eglGetScreensMESA");
82 return EGL_FALSE;
83 }
84
85 if (display->NumScreens > max_screens) {
86 n = max_screens;
87 }
88 else {
89 n = display->NumScreens;
90 }
91
92 if (screens) {
93 EGLint i;
94 for (i = 0; i < n; i++)
95 screens[i] = display->Screens[i]->Handle;
96 }
97 if (num_screens)
98 *num_screens = n;
99
100 return EGL_TRUE;
101 }
102
103
104 /**
105 * Create a drawing surface which can be directly displayed on a screen.
106 */
107 EGLSurface
108 _eglCreateScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
109 const EGLint *attrib_list)
110 {
111 _EGLSurface *surf;
112 EGLint width = 0, height = 0;
113 EGLint i;
114
115 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
116 switch (attrib_list[i]) {
117 case EGL_WIDTH:
118 width = attrib_list[++i];
119 break;
120 case EGL_HEIGHT:
121 height = attrib_list[++i];
122 break;
123 default:
124 _eglError(EGL_BAD_ATTRIBUTE, "eglCreateScreenSurfaceMESA");
125 return EGL_NO_SURFACE;
126 }
127 }
128
129 if (width <= 0 || height <= 0) {
130 _eglError(EGL_BAD_ATTRIBUTE,
131 "eglCreateScreenSurfaceMESA(width or height)");
132 return EGL_NO_SURFACE;
133 }
134
135 surf = (_EGLSurface *) malloc(sizeof(_EGLSurface));
136 _eglInitSurface(surf);
137 surf->Width = width;
138 surf->Height = height;
139 surf->Type = EGL_SCREEN_BIT_MESA;
140
141 /* insert into hash table */
142 _eglSaveSurface(surf);
143 assert(surf->Handle);
144
145 return surf->Handle;
146 }
147
148
149 /**
150 * Show the given surface on the named screen.
151 * If surface is EGL_NO_SURFACE, disable the screen's output.
152 *
153 * This is just a placeholder function; drivers will always override
154 * this with code that _really_ shows the surface.
155 */
156 EGLBoolean
157 _eglShowSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
158 EGLSurface surface)
159 {
160 _EGLScreen *scrn = _eglLookupScreen(dpy, screen);
161 _EGLMode *mode;
162
163 if (!scrn) {
164 _eglError(EGL_BAD_SCREEN_MESA, "eglShowSurfaceMESA");
165 return EGL_FALSE;
166 }
167
168 /*
169 * XXX: Check if the surface's configuration is compatible with the
170 * current screen mode.
171 */
172
173 mode = scrn->CurrentMode;
174 if (mode == EGL_NO_MODE_MESA) {
175 _eglError(EGL_BAD_MODE_MESA, "eglShowSurfaceMESA(no current mode)");
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 }
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 default:
294 _eglError(EGL_BAD_ATTRIBUTE, "eglQueryScreenMESA");
295 return EGL_FALSE;
296 }
297
298 return EGL_TRUE;
299 }
300
301
302
303 void
304 _eglDeleteScreen(_EGLScreen *scrn)
305 {
306 free(scrn->Modes);
307 free(scrn);
308 }
309