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