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