eglconfig.c revision 3464ebd5
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 */
56void
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 */
78PUBLIC 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
118enum {
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 */
136static 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 */
258EGLBoolean
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 */
428EGLBoolean
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
482static 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 */
502EGLBoolean
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 */
571EGLint
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
651static INLINE
652void _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 */
665void
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
703static 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 */
715EGLBoolean
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 */
764EGLBoolean
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
788static 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 */
800EGLBoolean
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}
812