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