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