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