egl: Fix _eglModeLookup.
[mesa.git] / src / egl / main / eglmode.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "egldisplay.h"
6 #include "egldriver.h"
7 #include "eglmode.h"
8 #include "eglcurrent.h"
9 #include "eglscreen.h"
10 #include "eglstring.h"
11
12
13 #ifdef EGL_MESA_screen_surface
14
15
16 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
17
18
19 /**
20 * Given an EGLModeMESA handle, return the corresponding _EGLMode object
21 * or null if non-existant.
22 */
23 _EGLMode *
24 _eglLookupMode(EGLModeMESA mode, _EGLDisplay *disp)
25 {
26 EGLint scrnum;
27
28 if (!disp || !disp->Screens)
29 return NULL;
30
31 /* loop over all screens on the display */
32 for (scrnum = 0; scrnum < disp->Screens->Size; scrnum++) {
33 const _EGLScreen *scrn = disp->Screens->Elements[scrnum];
34 EGLint idx;
35
36 /*
37 * the mode ids of a screen ranges from scrn->Handle to scrn->Handle +
38 * scrn->NumModes
39 */
40 if (mode >= scrn->Handle &&
41 mode < scrn->Handle + _EGL_SCREEN_MAX_MODES) {
42 idx = mode - scrn->Handle;
43
44 assert(idx < scrn->NumModes && scrn->Modes[idx].Handle == mode);
45
46 return &scrn->Modes[idx];
47 }
48 }
49
50 return NULL;
51 }
52
53
54 /**
55 * Parse the attrib_list to fill in the fields of the given _eglMode
56 * Return EGL_FALSE if any errors, EGL_TRUE otherwise.
57 */
58 static EGLBoolean
59 _eglParseModeAttribs(_EGLMode *mode, const EGLint *attrib_list)
60 {
61 EGLint i;
62
63 /* init all attribs to EGL_DONT_CARE */
64 mode->Handle = EGL_DONT_CARE;
65 mode->Width = EGL_DONT_CARE;
66 mode->Height = EGL_DONT_CARE;
67 mode->RefreshRate = EGL_DONT_CARE;
68 mode->Optimal = EGL_DONT_CARE;
69 mode->Interlaced = EGL_DONT_CARE;
70 mode->Name = NULL;
71
72 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
73 switch (attrib_list[i]) {
74 case EGL_MODE_ID_MESA:
75 mode->Handle = attrib_list[++i];
76 if (mode->Handle <= 0) {
77 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(handle)");
78 return EGL_FALSE;
79 }
80 break;
81 case EGL_WIDTH:
82 mode->Width = attrib_list[++i];
83 if (mode->Width <= 0) {
84 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(width)");
85 return EGL_FALSE;
86 }
87 break;
88 case EGL_HEIGHT:
89 mode->Height = attrib_list[++i];
90 if (mode->Height <= 0) {
91 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(height)");
92 return EGL_FALSE;
93 }
94 break;
95 case EGL_REFRESH_RATE_MESA:
96 mode->RefreshRate = attrib_list[++i];
97 if (mode->RefreshRate <= 0) {
98 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(refresh rate)");
99 return EGL_FALSE;
100 }
101 break;
102 case EGL_INTERLACED_MESA:
103 mode->Interlaced = attrib_list[++i];
104 if (mode->Interlaced != EGL_TRUE && mode->Interlaced != EGL_FALSE) {
105 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(interlaced)");
106 return EGL_FALSE;
107 }
108 break;
109 case EGL_OPTIMAL_MESA:
110 mode->Optimal = attrib_list[++i];
111 if (mode->Optimal != EGL_TRUE && mode->Optimal != EGL_FALSE) {
112 _eglError(EGL_BAD_PARAMETER, "eglChooseModeMESA(optimal)");
113 return EGL_FALSE;
114 }
115 break;
116 default:
117 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseModeMESA");
118 return EGL_FALSE;
119 }
120 }
121 return EGL_TRUE;
122 }
123
124
125 /**
126 * Determine if the candidate mode's attributes are at least as good
127 * as the minimal mode's.
128 * \return EGL_TRUE if qualifies, EGL_FALSE otherwise
129 */
130 static EGLBoolean
131 _eglModeQualifies(const _EGLMode *c, const _EGLMode *min)
132 {
133 if (min->Handle != EGL_DONT_CARE && c->Handle != min->Handle)
134 return EGL_FALSE;
135 if (min->Width != EGL_DONT_CARE && c->Width < min->Width)
136 return EGL_FALSE;
137 if (min->Height != EGL_DONT_CARE && c->Height < min->Height)
138 return EGL_FALSE;
139 if (min->RefreshRate != EGL_DONT_CARE && c->RefreshRate < min->RefreshRate)
140 return EGL_FALSE;
141 if (min->Optimal != EGL_DONT_CARE && c->Optimal != min->Optimal)
142 return EGL_FALSE;
143 if (min->Interlaced != EGL_DONT_CARE && c->Interlaced != min->Interlaced)
144 return EGL_FALSE;
145
146 return EGL_TRUE;
147 }
148
149
150 /**
151 * Return value of given mode attribute, or -1 if bad attrib.
152 */
153 static EGLint
154 getModeAttrib(const _EGLMode *m, EGLint attrib)
155 {
156 switch (attrib) {
157 case EGL_MODE_ID_MESA:
158 return m->Handle;
159 case EGL_WIDTH:
160 return m->Width;
161 case EGL_HEIGHT:
162 return m->Height;
163 case EGL_REFRESH_RATE_MESA:
164 return m->RefreshRate;
165 case EGL_OPTIMAL_MESA:
166 return m->Optimal;
167 case EGL_INTERLACED_MESA:
168 return m->Interlaced;
169 default:
170 return -1;
171 }
172 }
173
174
175 #define SMALLER 1
176 #define LARGER 2
177
178 struct sort_info {
179 EGLint Attrib;
180 EGLint Order; /* SMALLER or LARGER */
181 };
182
183 /* the order of these entries is the priority */
184 static struct sort_info SortInfo[] = {
185 { EGL_OPTIMAL_MESA, LARGER },
186 { EGL_INTERLACED_MESA, SMALLER },
187 { EGL_WIDTH, LARGER },
188 { EGL_HEIGHT, LARGER },
189 { EGL_REFRESH_RATE_MESA, LARGER },
190 { EGL_MODE_ID_MESA, SMALLER },
191 { 0, 0 }
192 };
193
194
195 /**
196 * Compare modes 'a' and 'b' and return -1 if a belongs before b, or 1 if a
197 * belongs after b, or 0 if they're equal.
198 * Used by qsort().
199 */
200 static int
201 _eglCompareModes(const void *a, const void *b)
202 {
203 const _EGLMode *aMode = *((const _EGLMode **) a);
204 const _EGLMode *bMode = *((const _EGLMode **) b);
205 EGLint i;
206
207 for (i = 0; SortInfo[i].Attrib; i++) {
208 const EGLint aVal = getModeAttrib(aMode, SortInfo[i].Attrib);
209 const EGLint bVal = getModeAttrib(bMode, SortInfo[i].Attrib);
210 if (aVal == bVal) {
211 /* a tie */
212 continue;
213 }
214 else if (SortInfo[i].Order == SMALLER) {
215 return (aVal < bVal) ? -1 : 1;
216 }
217 else if (SortInfo[i].Order == LARGER) {
218 return (aVal > bVal) ? -1 : 1;
219 }
220 }
221
222 /* all attributes identical */
223 return 0;
224 }
225
226
227 /**
228 * Search for EGLModes which match the given attribute list.
229 * Called via eglChooseModeMESA API function.
230 */
231 EGLBoolean
232 _eglChooseModeMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
233 const EGLint *attrib_list, EGLModeMESA *modes,
234 EGLint modes_size, EGLint *num_modes)
235 {
236 _EGLMode **modeList, min;
237 EGLint i, count;
238
239 if (!_eglParseModeAttribs(&min, attrib_list)) {
240 /* error code will have been recorded */
241 return EGL_FALSE;
242 }
243
244 /* allocate array of mode pointers */
245 modeList = (_EGLMode **) malloc(modes_size * sizeof(_EGLMode *));
246 if (!modeList) {
247 _eglError(EGL_BAD_MODE_MESA, "eglChooseModeMESA(out of memory)");
248 return EGL_FALSE;
249 }
250
251 /* make array of pointers to qualifying modes */
252 for (i = count = 0; i < scrn->NumModes && count < modes_size; i++) {
253 if (_eglModeQualifies(scrn->Modes + i, &min)) {
254 modeList[count++] = scrn->Modes + i;
255 }
256 }
257
258 /* sort array of pointers */
259 qsort(modeList, count, sizeof(_EGLMode *), _eglCompareModes);
260
261 /* copy mode handles to output array */
262 for (i = 0; i < count; i++) {
263 modes[i] = modeList[i]->Handle;
264 }
265
266 free(modeList);
267
268 *num_modes = count;
269
270 return EGL_TRUE;
271 }
272
273
274
275 /**
276 * Return all possible modes for the given screen. No sorting of results.
277 * Called via eglGetModesMESA() API function.
278 */
279 EGLBoolean
280 _eglGetModesMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLScreen *scrn,
281 EGLModeMESA *modes, EGLint modes_size, EGLint *num_modes)
282 {
283 if (modes) {
284 EGLint i;
285 *num_modes = MIN2(scrn->NumModes, modes_size);
286 for (i = 0; i < *num_modes; i++) {
287 modes[i] = scrn->Modes[i].Handle;
288 }
289 }
290 else {
291 /* just return total number of supported modes */
292 *num_modes = scrn->NumModes;
293 }
294
295 return EGL_TRUE;
296 }
297
298
299 /**
300 * Query an attribute of a mode.
301 */
302 EGLBoolean
303 _eglGetModeAttribMESA(_EGLDriver *drv, _EGLDisplay *dpy,
304 _EGLMode *m, EGLint attribute, EGLint *value)
305 {
306 EGLint v;
307
308 v = getModeAttrib(m, attribute);
309 if (v < 0) {
310 _eglError(EGL_BAD_ATTRIBUTE, "eglGetModeAttribMESA");
311 return EGL_FALSE;
312 }
313 *value = v;
314 return EGL_TRUE;
315 }
316
317
318 /**
319 * Return human-readable string for given mode.
320 * This is the default function called by eglQueryModeStringMESA().
321 */
322 const char *
323 _eglQueryModeStringMESA(_EGLDriver *drv, _EGLDisplay *dpy, _EGLMode *m)
324 {
325 return m->Name;
326 }
327
328
329 #endif /* EGL_MESA_screen_surface */