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