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