egl: Allow a prioritized list of default drivers
[mesa.git] / src / egl / main / eglconfig.c
1 /**
2 * EGL Configuration (pixel format) functions.
3 */
4
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include "eglconfig.h"
10 #include "egldisplay.h"
11 #include "eglcurrent.h"
12 #include "egllog.h"
13
14
15 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
16
17
18 /**
19 * Init the given _EGLconfig to default values.
20 * \param id the configuration's ID.
21 *
22 * Note that id must be positive for the config to be valid.
23 * It is also recommended that when there are N configs, their
24 * IDs are from 1 to N respectively.
25 */
26 void
27 _eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id)
28 {
29 memset(config, 0, sizeof(*config));
30
31 config->Display = dpy;
32
33 /* some attributes take non-zero default values */
34 SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id);
35 SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_NONE);
36 SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE);
37 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_NONE);
38 #ifdef EGL_VERSION_1_2
39 SET_CONFIG_ATTRIB(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
40 #endif /* EGL_VERSION_1_2 */
41 }
42
43
44 /**
45 * Link a config to a display and return the handle of the link.
46 * The handle can be passed to client directly.
47 *
48 * Note that we just save the ptr to the config (we don't copy the config).
49 */
50 EGLConfig
51 _eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf)
52 {
53 _EGLConfig **configs;
54
55 /* sanity check */
56 assert(GET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID) > 0);
57
58 configs = dpy->Configs;
59 if (dpy->NumConfigs >= dpy->MaxConfigs) {
60 EGLint new_size = dpy->MaxConfigs + 16;
61 assert(dpy->NumConfigs < new_size);
62
63 configs = realloc(dpy->Configs, new_size * sizeof(dpy->Configs[0]));
64 if (!configs)
65 return (EGLConfig) NULL;
66
67 dpy->Configs = configs;
68 dpy->MaxConfigs = new_size;
69 }
70
71 conf->Display = dpy;
72 dpy->Configs[dpy->NumConfigs++] = conf;
73
74 return (EGLConfig) conf;
75 }
76
77
78 EGLBoolean
79 _eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy)
80 {
81 EGLint num_configs = (dpy) ? dpy->NumConfigs : 0;
82 EGLint i;
83
84 for (i = 0; i < num_configs; i++) {
85 _EGLConfig *conf = dpy->Configs[i];
86 if (conf == (_EGLConfig *) config) {
87 assert(conf->Display == dpy);
88 break;
89 }
90 }
91 return (i < num_configs);
92 }
93
94
95 enum {
96 /* types */
97 ATTRIB_TYPE_INTEGER,
98 ATTRIB_TYPE_BOOLEAN,
99 ATTRIB_TYPE_BITMASK,
100 ATTRIB_TYPE_ENUM,
101 ATTRIB_TYPE_PSEUDO, /* non-queryable */
102 ATTRIB_TYPE_PLATFORM, /* platform-dependent */
103 /* criteria */
104 ATTRIB_CRITERION_EXACT,
105 ATTRIB_CRITERION_ATLEAST,
106 ATTRIB_CRITERION_MASK,
107 ATTRIB_CRITERION_SPECIAL,
108 ATTRIB_CRITERION_IGNORE
109 };
110
111
112 /* EGL spec Table 3.1 and 3.4 */
113 static const struct {
114 EGLint attr;
115 EGLint type;
116 EGLint criterion;
117 EGLint default_value;
118 } _eglValidationTable[] =
119 {
120 { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
121 ATTRIB_CRITERION_ATLEAST,
122 0 },
123 { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER,
124 ATTRIB_CRITERION_ATLEAST,
125 0 },
126 { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER,
127 ATTRIB_CRITERION_ATLEAST,
128 0 },
129 { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER,
130 ATTRIB_CRITERION_ATLEAST,
131 0 },
132 { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER,
133 ATTRIB_CRITERION_ATLEAST,
134 0 },
135 { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER,
136 ATTRIB_CRITERION_ATLEAST,
137 0 },
138 { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER,
139 ATTRIB_CRITERION_ATLEAST,
140 0 },
141 { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN,
142 ATTRIB_CRITERION_EXACT,
143 EGL_DONT_CARE },
144 { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN,
145 ATTRIB_CRITERION_EXACT,
146 EGL_DONT_CARE },
147 { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM,
148 ATTRIB_CRITERION_EXACT,
149 EGL_RGB_BUFFER },
150 { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM,
151 ATTRIB_CRITERION_EXACT,
152 EGL_DONT_CARE },
153 { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER,
154 ATTRIB_CRITERION_EXACT,
155 EGL_DONT_CARE },
156 { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK,
157 ATTRIB_CRITERION_MASK,
158 0 },
159 { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER,
160 ATTRIB_CRITERION_ATLEAST,
161 0 },
162 { EGL_LEVEL, ATTRIB_TYPE_PLATFORM,
163 ATTRIB_CRITERION_EXACT,
164 0 },
165 { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER,
166 ATTRIB_CRITERION_IGNORE,
167 0 },
168 { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER,
169 ATTRIB_CRITERION_IGNORE,
170 0 },
171 { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER,
172 ATTRIB_CRITERION_IGNORE,
173 0 },
174 { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
175 ATTRIB_CRITERION_EXACT,
176 EGL_DONT_CARE },
177 { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
178 ATTRIB_CRITERION_EXACT,
179 EGL_DONT_CARE },
180 { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN,
181 ATTRIB_CRITERION_EXACT,
182 EGL_DONT_CARE },
183 { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM,
184 ATTRIB_CRITERION_IGNORE,
185 0 },
186 { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM,
187 ATTRIB_CRITERION_EXACT,
188 EGL_DONT_CARE },
189 { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK,
190 ATTRIB_CRITERION_MASK,
191 EGL_OPENGL_ES_BIT },
192 { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER,
193 ATTRIB_CRITERION_ATLEAST,
194 0 },
195 { EGL_SAMPLES, ATTRIB_TYPE_INTEGER,
196 ATTRIB_CRITERION_ATLEAST,
197 0 },
198 { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER,
199 ATTRIB_CRITERION_ATLEAST,
200 0 },
201 { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK,
202 ATTRIB_CRITERION_MASK,
203 EGL_WINDOW_BIT },
204 { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM,
205 ATTRIB_CRITERION_EXACT,
206 EGL_NONE },
207 { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER,
208 ATTRIB_CRITERION_EXACT,
209 EGL_DONT_CARE },
210 { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER,
211 ATTRIB_CRITERION_EXACT,
212 EGL_DONT_CARE },
213 { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
214 ATTRIB_CRITERION_EXACT,
215 EGL_DONT_CARE },
216 /* these are not real attributes */
217 { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
218 ATTRIB_CRITERION_SPECIAL,
219 EGL_NONE },
220 /* there is a gap before EGL_SAMPLES */
221 { 0x3030, ATTRIB_TYPE_PSEUDO,
222 ATTRIB_CRITERION_IGNORE,
223 0 },
224 { EGL_NONE, ATTRIB_TYPE_PSEUDO,
225 ATTRIB_CRITERION_IGNORE,
226 0 }
227 };
228
229
230 /**
231 * Return true if a config is valid. When for_matching is true,
232 * EGL_DONT_CARE is accepted as a valid attribute value, and checks
233 * for conflicting attribute values are skipped.
234 *
235 * Note that some attributes are platform-dependent and are not
236 * checked.
237 */
238 EGLBoolean
239 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
240 {
241 EGLint i, attr, val;
242 EGLBoolean valid = EGL_TRUE;
243 EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0;
244 EGLint alpha_size = 0, buffer_size = 0;
245
246 /* all attributes should have been listed */
247 assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS);
248
249 /* check attributes by their types */
250 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
251 EGLint mask;
252
253 attr = _eglValidationTable[i].attr;
254 val = GET_CONFIG_ATTRIB(conf, attr);
255
256 switch (_eglValidationTable[i].type) {
257 case ATTRIB_TYPE_INTEGER:
258 switch (attr) {
259 case EGL_CONFIG_ID:
260 /* config id must be positive */
261 if (val <= 0)
262 valid = EGL_FALSE;
263 break;
264 case EGL_SAMPLE_BUFFERS:
265 /* there can be at most 1 sample buffer */
266 if (val > 1)
267 valid = EGL_FALSE;
268 break;
269 case EGL_RED_SIZE:
270 red_size = val;
271 break;
272 case EGL_GREEN_SIZE:
273 green_size = val;
274 break;
275 case EGL_BLUE_SIZE:
276 blue_size = val;
277 break;
278 case EGL_LUMINANCE_SIZE:
279 luminance_size = val;
280 break;
281 case EGL_ALPHA_SIZE:
282 alpha_size = val;
283 break;
284 case EGL_BUFFER_SIZE:
285 buffer_size = val;
286 break;
287 }
288 if (val < 0)
289 valid = EGL_FALSE;
290 break;
291 case ATTRIB_TYPE_BOOLEAN:
292 if (val != EGL_TRUE && val != EGL_FALSE)
293 valid = EGL_FALSE;
294 break;
295 case ATTRIB_TYPE_ENUM:
296 switch (attr) {
297 case EGL_CONFIG_CAVEAT:
298 if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
299 val != EGL_NON_CONFORMANT_CONFIG)
300 valid = EGL_FALSE;
301 break;
302 case EGL_TRANSPARENT_TYPE:
303 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
304 valid = EGL_FALSE;
305 break;
306 case EGL_COLOR_BUFFER_TYPE:
307 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
308 valid = EGL_FALSE;
309 break;
310 default:
311 assert(0);
312 break;
313 }
314 break;
315 case ATTRIB_TYPE_BITMASK:
316 switch (attr) {
317 case EGL_SURFACE_TYPE:
318 mask = EGL_PBUFFER_BIT |
319 EGL_PIXMAP_BIT |
320 EGL_WINDOW_BIT |
321 EGL_VG_COLORSPACE_LINEAR_BIT |
322 EGL_VG_ALPHA_FORMAT_PRE_BIT |
323 EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
324 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
325 if (conf->Display->Extensions.MESA_screen_surface)
326 mask |= EGL_SCREEN_BIT_MESA;
327 break;
328 case EGL_RENDERABLE_TYPE:
329 case EGL_CONFORMANT:
330 mask = EGL_OPENGL_ES_BIT |
331 EGL_OPENVG_BIT |
332 EGL_OPENGL_ES2_BIT |
333 EGL_OPENGL_BIT;
334 break;
335 default:
336 assert(0);
337 break;
338 }
339 if (val & ~mask)
340 valid = EGL_FALSE;
341 break;
342 case ATTRIB_TYPE_PLATFORM:
343 /* unable to check platform-dependent attributes here */
344 break;
345 case ATTRIB_TYPE_PSEUDO:
346 /* pseudo attributes should not be set */
347 if (val != 0)
348 valid = EGL_FALSE;
349 break;
350 default:
351 assert(0);
352 break;
353 }
354
355 if (!valid && for_matching) {
356 /* accept EGL_DONT_CARE as a valid value */
357 if (val == EGL_DONT_CARE)
358 valid = EGL_TRUE;
359 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
360 valid = EGL_TRUE;
361 }
362 if (!valid) {
363 _eglLog(_EGL_DEBUG,
364 "attribute 0x%04x has an invalid value 0x%x", attr, val);
365 break;
366 }
367 }
368
369 /* any invalid attribute value should have been catched */
370 if (!valid || for_matching)
371 return valid;
372
373 /* now check for conflicting attribute values */
374
375 switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) {
376 case EGL_RGB_BUFFER:
377 if (luminance_size)
378 valid = EGL_FALSE;
379 if (red_size + green_size + blue_size + alpha_size != buffer_size)
380 valid = EGL_FALSE;
381 break;
382 case EGL_LUMINANCE_BUFFER:
383 if (red_size || green_size || blue_size)
384 valid = EGL_FALSE;
385 if (luminance_size + alpha_size != buffer_size)
386 valid = EGL_FALSE;
387 break;
388 }
389 if (!valid) {
390 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
391 return EGL_FALSE;
392 }
393
394 val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS);
395 if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES))
396 valid = EGL_FALSE;
397 if (!valid) {
398 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
399 return EGL_FALSE;
400 }
401
402 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
403 if (!(val & EGL_WINDOW_BIT)) {
404 if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 ||
405 GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE)
406 valid = EGL_FALSE;
407 }
408 if (!(val & EGL_PBUFFER_BIT)) {
409 if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) ||
410 GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA))
411 valid = EGL_FALSE;
412 }
413 if (!valid) {
414 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
415 return EGL_FALSE;
416 }
417
418 return valid;
419 }
420
421
422 /**
423 * Return true if a config matches the criteria. This and
424 * _eglParseConfigAttribList together implement the algorithm
425 * described in "Selection of EGLConfigs".
426 *
427 * Note that attributes that are special (currently, only
428 * EGL_MATCH_NATIVE_PIXMAP) are ignored.
429 */
430 EGLBoolean
431 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
432 {
433 EGLint attr, val, i;
434 EGLBoolean matched = EGL_TRUE;
435
436 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
437 EGLint cmp;
438 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
439 continue;
440
441 attr = _eglValidationTable[i].attr;
442 cmp = GET_CONFIG_ATTRIB(criteria, attr);
443 if (cmp == EGL_DONT_CARE)
444 continue;
445
446 val = GET_CONFIG_ATTRIB(conf, attr);
447 switch (_eglValidationTable[i].criterion) {
448 case ATTRIB_CRITERION_EXACT:
449 if (val != cmp)
450 matched = EGL_FALSE;
451 break;
452 case ATTRIB_CRITERION_ATLEAST:
453 if (val < cmp)
454 matched = EGL_FALSE;
455 break;
456 case ATTRIB_CRITERION_MASK:
457 if ((val & cmp) != cmp)
458 matched = EGL_FALSE;
459 break;
460 case ATTRIB_CRITERION_SPECIAL:
461 /* ignored here */
462 break;
463 default:
464 assert(0);
465 break;
466 }
467
468 if (!matched) {
469 #ifdef DEBUG
470 _eglLog(_EGL_DEBUG,
471 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
472 val, attr, cmp);
473 #endif
474 break;
475 }
476 }
477
478 return matched;
479 }
480
481
482 /**
483 * Initialize a criteria config from the given attribute list.
484 * Return EGL_FALSE if any of the attribute is invalid.
485 */
486 EGLBoolean
487 _eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
488 {
489 EGLint attr, val, i;
490 EGLint config_id = 0, level = 0;
491 EGLBoolean has_native_visual_type = EGL_FALSE;
492 EGLBoolean has_transparent_color = EGL_FALSE;
493
494 /* reset to default values */
495 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
496 attr = _eglValidationTable[i].attr;
497 val = _eglValidationTable[i].default_value;
498 SET_CONFIG_ATTRIB(conf, attr, val);
499 }
500
501 /* parse the list */
502 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
503 EGLint idx;
504
505 attr = attrib_list[i];
506 val = attrib_list[i + 1];
507
508 idx = _eglIndexConfig(conf, attr);
509 if (idx < 0)
510 return EGL_FALSE;
511 conf->Storage[idx] = val;
512
513 /* rememeber some attributes for post-processing */
514 switch (attr) {
515 case EGL_CONFIG_ID:
516 config_id = val;
517 break;
518 case EGL_LEVEL:
519 level = val;
520 break;
521 case EGL_NATIVE_VISUAL_TYPE:
522 has_native_visual_type = EGL_TRUE;
523 break;
524 case EGL_TRANSPARENT_RED_VALUE:
525 case EGL_TRANSPARENT_GREEN_VALUE:
526 case EGL_TRANSPARENT_BLUE_VALUE:
527 has_transparent_color = EGL_TRUE;
528 break;
529 default:
530 break;
531 }
532 }
533
534 if (!_eglValidateConfig(conf, EGL_TRUE))
535 return EGL_FALSE;
536
537 /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
538 if (level == EGL_DONT_CARE)
539 return EGL_FALSE;
540
541 /* ignore other attributes when EGL_CONFIG_ID is given */
542 if (config_id > 0) {
543 _eglResetConfigKeys(conf, EGL_DONT_CARE);
544 SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id);
545 }
546 else {
547 if (has_native_visual_type) {
548 val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
549 if (!(val & EGL_WINDOW_BIT))
550 SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
551 }
552
553 if (has_transparent_color) {
554 val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE);
555 if (val == EGL_NONE) {
556 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE,
557 EGL_DONT_CARE);
558 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE,
559 EGL_DONT_CARE);
560 SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE,
561 EGL_DONT_CARE);
562 }
563 }
564 }
565
566 return EGL_TRUE;
567 }
568
569
570 /**
571 * Decide the ordering of conf1 and conf2, under the given criteria.
572 * When compare_id is true, this implements the algorithm described
573 * in "Sorting of EGLConfigs". When compare_id is false,
574 * EGL_CONFIG_ID is not compared.
575 *
576 * It returns a negative integer if conf1 is considered to come
577 * before conf2; a positive integer if conf2 is considered to come
578 * before conf1; zero if the ordering cannot be decided.
579 *
580 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
581 * ignored here.
582 */
583 EGLint
584 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
585 const _EGLConfig *criteria, EGLBoolean compare_id)
586 {
587 const EGLint compare_attribs[] = {
588 EGL_BUFFER_SIZE,
589 EGL_SAMPLE_BUFFERS,
590 EGL_SAMPLES,
591 EGL_DEPTH_SIZE,
592 EGL_STENCIL_SIZE,
593 EGL_ALPHA_MASK_SIZE,
594 };
595 EGLint val1, val2;
596 EGLBoolean rgb_buffer;
597 EGLint i;
598
599 if (conf1 == conf2)
600 return 0;
601
602 /* the enum values have the desired ordering */
603 assert(EGL_NONE < EGL_SLOW_CONFIG);
604 assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
605 val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT);
606 val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT);
607 if (val1 != val2)
608 return (val1 - val2);
609
610 /* the enum values have the desired ordering */
611 assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
612 val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE);
613 val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE);
614 if (val1 != val2)
615 return (val1 - val2);
616 rgb_buffer = (val1 == EGL_RGB_BUFFER);
617
618 if (criteria) {
619 val1 = val2 = 0;
620 if (rgb_buffer) {
621 if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) {
622 val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE);
623 val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE);
624 }
625 if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) {
626 val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE);
627 val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE);
628 }
629 if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) {
630 val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE);
631 val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE);
632 }
633 }
634 else {
635 if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) {
636 val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE);
637 val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE);
638 }
639 }
640 if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) {
641 val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE);
642 val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE);
643 }
644 }
645 else {
646 /* assume the default criteria, which gives no specific ordering */
647 val1 = val2 = 0;
648 }
649
650 /* for color bits, larger one is preferred */
651 if (val1 != val2)
652 return (val2 - val1);
653
654 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
655 val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]);
656 val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]);
657 if (val1 != val2)
658 return (val1 - val2);
659 }
660
661 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
662
663 if (compare_id) {
664 val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID);
665 val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID);
666 assert(val1 != val2);
667 }
668 else {
669 val1 = val2 = 0;
670 }
671
672 return (val1 - val2);
673 }
674
675
676 static INLINE
677 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
678 {
679 const _EGLConfig *tmp = *conf1;
680 *conf1 = *conf2;
681 *conf2 = tmp;
682 }
683
684
685 /**
686 * Quick sort an array of configs. This differs from the standard
687 * qsort() in that the compare function accepts an additional
688 * argument.
689 */
690 void
691 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
692 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
693 void *),
694 void *priv_data)
695 {
696 const EGLint pivot = 0;
697 EGLint i, j;
698
699 if (count <= 1)
700 return;
701
702 _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
703 i = 1;
704 j = count - 1;
705 do {
706 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
707 i++;
708 while (compare(configs[j], configs[pivot], priv_data) > 0)
709 j--;
710 if (i < j) {
711 _eglSwapConfigs(&configs[i], &configs[j]);
712 i++;
713 j--;
714 }
715 else if (i == j) {
716 i++;
717 j--;
718 break;
719 }
720 } while (i <= j);
721 _eglSwapConfigs(&configs[pivot], &configs[j]);
722
723 _eglSortConfigs(configs, j, compare, priv_data);
724 _eglSortConfigs(configs + i, count - i, compare, priv_data);
725 }
726
727
728 static int
729 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
730 void *priv_data)
731 {
732 const _EGLConfig *criteria = (const _EGLConfig *) priv_data;
733 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
734 }
735
736
737 /**
738 * Typical fallback routine for eglChooseConfig
739 */
740 EGLBoolean
741 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
742 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
743 {
744 _EGLConfig **configList, criteria;
745 EGLint i, count;
746
747 if (!num_configs)
748 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
749
750 _eglInitConfig(&criteria, disp, 0);
751 if (!_eglParseConfigAttribList(&criteria, attrib_list))
752 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
753
754 /* allocate array of config pointers */
755 configList = (_EGLConfig **)
756 malloc(disp->NumConfigs * sizeof(_EGLConfig *));
757 if (!configList)
758 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
759
760 /* perform selection of configs */
761 count = 0;
762 for (i = 0; i < disp->NumConfigs; i++) {
763 if (_eglMatchConfig(disp->Configs[i], &criteria))
764 configList[count++] = disp->Configs[i];
765 }
766
767 /* perform sorting of configs */
768 if (configs && count) {
769 _eglSortConfigs((const _EGLConfig **) configList, count,
770 _eglFallbackCompare, (void *) &criteria);
771 count = MIN2(count, config_size);
772 for (i = 0; i < count; i++)
773 configs[i] = _eglGetConfigHandle(configList[i]);
774 }
775
776 free(configList);
777
778 *num_configs = count;
779
780 return EGL_TRUE;
781 }
782
783
784 static INLINE EGLBoolean
785 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
786 {
787 if (_eglIndexConfig(conf, attr) < 0)
788 return EGL_FALSE;
789
790 /* there are some holes in the range */
791 switch (attr) {
792 case 0x3030 /* a gap before EGL_SAMPLES */:
793 case EGL_NONE:
794 #ifdef EGL_VERSION_1_4
795 case EGL_MATCH_NATIVE_PIXMAP:
796 #endif
797 return EGL_FALSE;
798 default:
799 break;
800 }
801
802 return EGL_TRUE;
803 }
804
805
806 /**
807 * Fallback for eglGetConfigAttrib.
808 */
809 EGLBoolean
810 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
811 EGLint attribute, EGLint *value)
812 {
813 if (!_eglIsConfigAttribValid(conf, attribute))
814 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
815 if (!value)
816 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
817
818 *value = GET_CONFIG_ATTRIB(conf, attribute);
819 return EGL_TRUE;
820 }
821
822
823 /**
824 * Fallback for eglGetConfigs.
825 */
826 EGLBoolean
827 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
828 EGLint config_size, EGLint *num_config)
829 {
830 if (!num_config)
831 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
832
833 if (configs) {
834 EGLint i;
835 *num_config = MIN2(disp->NumConfigs, config_size);
836 for (i = 0; i < *num_config; i++)
837 configs[i] = _eglGetConfigHandle(disp->Configs[i]);
838 }
839 else {
840 /* just return total number of supported configs */
841 *num_config = disp->NumConfigs;
842 }
843
844 return EGL_TRUE;
845 }