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