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