74333926d90b386ea6415fc4daa892eb164ce2b8
[mesa.git] / src / egl / main / eglmode.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "egldisplay.h"
36 #include "eglmode.h"
37 #include "eglcurrent.h"
38 #include "eglscreen.h"
39
40
41 #ifdef EGL_MESA_screen_surface
42
43
44 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
45
46
47 /**
48 * Given an EGLModeMESA handle, return the corresponding _EGLMode object
49 * or null if non-existant.
50 */
51 _EGLMode *
52 _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
53 {
54 EGLint scrnum;
55
56 if (!disp || !disp->Screens)
57 return NULL;
58
59 /* loop over all screens on the display */
60 for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
61 const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
62 EGLint idx;
63
64 /*
65 * the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
66 * scrn->NumModes
67 */
68 if (mode >= scrn->Handle &&
69 mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
70 idx = mode - scrn->Handle;
71
72 assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
73
74 return &scrn->Modes[idx];
75 }
76 }
77
78 return NULL;
79 }
80
81
82 /**
83 * Parse the attrib_list to fill in the fields of the given _eglMode
84 * Return EGL_FALSE if any errors, EGL_TRUE otherwise.
85 */
86 static EGLBoolean
87 _eglParseModeAttribs(_EGLMode *mode, const EGLint *attrib_list)
88 {
89 EGLint i;
90
91 /* init all attribs to EGL_DONT_CARE */
92 mode->Handle = EGL_DONT_CARE;
93 mode->Width = EGL_DONT_CARE;
94 mode->Height = EGL_DONT_CARE;
95 mode->RefreshRate = EGL_DONT_CARE;
96 mode->Optimal = EGL_DONT_CARE;
97 mode->Interlaced = EGL_DONT_CARE;
98 mode->Name = NULL;
99
100 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
101 switch (attrib_list[i]) {
102 case EGL_MODE_ID_MESA:
103 mode->Handle = attrib_list[++i];
104 if (mode->Handle <= 0) {
105 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(handle)");
106 return EGL_FALSE;
107 }
108 break;
109 case EGL_WIDTH:
110 mode->Width = attrib_list[++i];
111 if (mode->Width <= 0) {
112 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(width)");
113 return EGL_FALSE;
114 }
115 break;
116 case EGL_HEIGHT:
117 mode->Height = attrib_list[++i];
118 if (mode->Height <= 0) {
119 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(height)");
120 return EGL_FALSE;
121 }
122 break;
123 case EGL_REFRESH_RATE_MESA:
124 mode->RefreshRate = attrib_list[++i];
125 if (mode->RefreshRate <= 0) {
126 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(refresh rate)");
127 return EGL_FALSE;
128 }
129 break;
130 case EGL_INTERLACED_MESA:
131 mode->Interlaced = attrib_list[++i];
132 if (mode->Interlaced != EGL_TRUE && mode->Interlaced != EGL_FALSE) {
133 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(interlaced)");
134 return EGL_FALSE;
135 }
136 break;
137 case EGL_OPTIMAL_MESA:
138 mode->Optimal = attrib_list[++i];
139 if (mode->Optimal != EGL_TRUE && mode->Optimal != EGL_FALSE) {
140 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(optimal)");
141 return EGL_FALSE;
142 }
143 break;
144 default:
145 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseModeMESA");
146 return EGL_FALSE;
147 }
148 }
149 return EGL_TRUE;
150 }
151
152
153 /**
154 * Determine if the candidate mode's attributes are at least as good
155 * as the minimal mode's.
156 * \return EGL_TRUE if qualifies, EGL_FALSE otherwise
157 */
158 static EGLBoolean
159 _eglModeQualifies(const _EGLMode *c, const _EGLMode *min)
160 {
161 if (min->Handle != EGL_DONT_CARE && c->Handle != min->Handle)
162 return EGL_FALSE;
163 if (min->Width != EGL_DONT_CARE && c->Width < min->Width)
164 return EGL_FALSE;
165 if (min->Height != EGL_DONT_CARE && c->Height < min->Height)
166 return EGL_FALSE;
167 if (min->RefreshRate != EGL_DONT_CARE && c->RefreshRate < min->RefreshRate)
168 return EGL_FALSE;
169 if (min->Optimal != EGL_DONT_CARE && c->Optimal != min->Optimal)
170 return EGL_FALSE;
171 if (min->Interlaced != EGL_DONT_CARE && c->Interlaced != min->Interlaced)
172 return EGL_FALSE;
173
174 return EGL_TRUE;
175 }
176
177
178 /**
179 * Return value of given mode attribute, or -1 if bad attrib.
180 */
181 static EGLint
182 getModeAttrib(const _EGLMode *m, EGLint attrib)
183 {
184 switch (attrib) {
185 case EGL_MODE_ID_MESA:
186 return m->Handle;
187 case EGL_WIDTH:
188 return m->Width;
189 case EGL_HEIGHT:
190 return m->Height;
191 case EGL_REFRESH_RATE_MESA:
192 return m->RefreshRate;
193 case EGL_OPTIMAL_MESA:
194 return m->Optimal;
195 case EGL_INTERLACED_MESA:
196 return m->Interlaced;
197 default:
198 return -1;
199 }
200 }
201
202
203 #define SMALLER 1
204 #define LARGER 2
205
206 struct sort_info {
207 EGLint Attrib;
208 EGLint Order; /* SMALLER or LARGER */
209 };
210
211 /* the order of these entries is the priority */
212 static struct sort_info SortInfo[] = {
213 { EGL_OPTIMAL_MESA, LARGER },
214 { EGL_INTERLACED_MESA, SMALLER },
215 { EGL_WIDTH, LARGER },
216 { EGL_HEIGHT, LARGER },
217 { EGL_REFRESH_RATE_MESA, LARGER },
218 { EGL_MODE_ID_MESA, SMALLER },
219 { 0, 0 }
220 };
221
222
223 /**
224 * Compare modes 'a' and 'b' and return -1 if a belongs before b, or 1 if a
225 * belongs after b, or 0 if they're equal.
226 * Used by qsort().
227 */
228 static int
229 _eglCompareModes(const void *a, const void *b)
230 {
231 const _EGLMode *aMode = *((const _EGLMode **) a);
232 const _EGLMode *bMode = *((const _EGLMode **) b);
233 EGLint i;
234
235 for (i = 0; SortInfo[i].Attrib; i++) {
236 const EGLint aVal = getModeAttrib(aMode, SortInfo[i].Attrib);
237 const EGLint bVal = getModeAttrib(bMode, SortInfo[i].Attrib);
238 if (aVal == bVal) {
239 /* a tie */
240 continue;
241 }
242 else if (SortInfo[i].Order == SMALLER) {
243 return (aVal < bVal) ? -1 : 1;
244 }
245 else if (SortInfo[i].Order == LARGER) {
246 return (aVal > bVal) ? -1 : 1;
247 }
248 }
249
250 /* all attributes identical */
251 return 0;
252 }
253
254
255 /**
256 * Search for EGLModes which match the given attribute list.
257 * Called via eglChooseModeMESA API function.
258 */
259 EGLBoolean
260 _eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
261 const EGLint *attrib_list, EGLModeMESA *modes,
262 EGLint modes_size, EGLint *num_modes)
263 {
264 _EGLMode **modeList, min;
265 EGLint i, count;
266
267 if (!_eglParseModeAttribs(&min, attrib_list)) {
268 /* error code will have been recorded */
269 return EGL_FALSE;
270 }
271
272 /* allocate array of mode pointers */
273 modeList = malloc(modes_size * sizeof(_EGLMode *));
274 if (!modeList) {
275 _eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)");
276 return EGL_FALSE;
277 }
278
279 /* make array of pointers to qualifying modes */
280 for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) {
281 if (_eglModeQualifies(scrn->Modes + i, &min)) {
282 modeList[count++] = scrn->Modes + i;
283 }
284 }
285
286 /* sort array of pointers */
287 qsort(modeList, count, sizeof(_EGLMode *), _eglCompareModes);
288
289 /* copy mode handles to output array */
290 for (i = 0; i < count; i++) {
291 modes[i] = modeList[i]->Handle;
292 }
293
294 free(modeList);
295
296 *num_modes = count;
297
298 return EGL_TRUE;
299 }
300
301
302
303 /**
304 * Return all possible modes for the given screen. No sorting of results.
305 * Called via eglGetModesMESA() API function.
306 */
307 EGLBoolean
308 _eglGetModesMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
309 EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
310 {
311 if (modes) {
312 EGLint i;
313 *num_modes = MIN2(scrn->NumModes, modes_size);
314 for (i = 0; i < *num_modes; i++) {
315 modes[i] = scrn->Modes[i].Handle;
316 }
317 }
318 else {
319 /* just return total number of supported modes */
320 *num_modes = scrn->NumModes;
321 }
322
323 return EGL_TRUE;
324 }
325
326
327 /**
328 * Query an attribute of a mode.
329 */
330 EGLBoolean
331 _eglGetModeAttribMESA(_EGLDriver *drv, _EGLDisplay *dpy,
332 _EGLMode *m, EGLint attribute, EGLint *value)
333 {
334 EGLint v;
335
336 v = getModeAttrib(m, attribute);
337 if (v < 0) {
338 _eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA");
339 return EGL_FALSE;
340 }
341 *value = v;
342 return EGL_TRUE;
343 }
344
345
346 /**
347 * Return human-readable string for given mode.
348 * This is the default function called by eglQueryModeStringMESA().
349 */
350 const char *
351 _eglQueryModeStringMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLMode *m)
352 {
353 return m->Name;
354 }
355
356
357 #endif /* EGL_MESA_screen_surface */