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