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