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