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            mask = 0;
339            break;
340         }
341         if (val & ~mask)
342            valid = EGL_FALSE;
343         break;
344      case ATTRIB_TYPE_PLATFORM:
345         /* unable to check platform-dependent attributes here */
346         break;
347      case ATTRIB_TYPE_PSEUDO:
348         /* pseudo attributes should not be set */
349         if (val != 0)
350            valid = EGL_FALSE;
351         break;
352      default:
353         assert(0);
354         break;
355      }
356
357      if (!valid && for_matching) {
358         /* accept EGL_DONT_CARE as a valid value */
359         if (val == EGL_DONT_CARE)
360            valid = EGL_TRUE;
361         if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
362            valid = EGL_TRUE;
363      }
364      if (!valid) {
365         _eglLog(_EGL_DEBUG,
366               "attribute 0x%04x has an invalid value 0x%x", attr, val);
367         break;
368      }
369   }
370
371   /* any invalid attribute value should have been catched */
372   if (!valid || for_matching)
373      return valid;
374
375   /* now check for conflicting attribute values */
376
377   switch (conf->ColorBufferType) {
378   case EGL_RGB_BUFFER:
379      if (conf->LuminanceSize)
380         valid = EGL_FALSE;
381      if (conf->RedSize + conf->GreenSize +
382            conf->BlueSize + conf->AlphaSize != conf->BufferSize)
383         valid = EGL_FALSE;
384      break;
385   case EGL_LUMINANCE_BUFFER:
386      if (conf->RedSize || conf->GreenSize || conf->BlueSize)
387         valid = EGL_FALSE;
388      if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
389         valid = EGL_FALSE;
390      break;
391   }
392   if (!valid) {
393      _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
394      return EGL_FALSE;
395   }
396
397   if (!conf->SampleBuffers && conf->Samples)
398      valid = EGL_FALSE;
399   if (!valid) {
400      _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
401      return EGL_FALSE;
402   }
403
404   if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
405      if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
406         valid = EGL_FALSE;
407   }
408   if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
409      if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
410         valid = EGL_FALSE;
411   }
412   if (!valid) {
413      _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
414      return EGL_FALSE;
415   }
416
417   return valid;
418}
419
420
421/**
422 * Return true if a config matches the criteria.  This and
423 * _eglParseConfigAttribList together implement the algorithm
424 * described in "Selection of EGLConfigs".
425 *
426 * Note that attributes that are special (currently, only
427 * EGL_MATCH_NATIVE_PIXMAP) are ignored.
428 */
429EGLBoolean
430_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
431{
432   EGLint attr, val, i;
433   EGLBoolean matched = EGL_TRUE;
434
435   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
436      EGLint cmp;
437      if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
438         continue;
439
440      attr = _eglValidationTable[i].attr;
441      cmp = _eglGetConfigKey(criteria, attr);
442      if (cmp == EGL_DONT_CARE)
443         continue;
444
445      val = _eglGetConfigKey(conf, attr);
446      switch (_eglValidationTable[i].criterion) {
447      case ATTRIB_CRITERION_EXACT:
448         if (val != cmp)
449            matched = EGL_FALSE;
450         break;
451      case ATTRIB_CRITERION_ATLEAST:
452         if (val < cmp)
453            matched = EGL_FALSE;
454         break;
455      case ATTRIB_CRITERION_MASK:
456         if ((val & cmp) != cmp)
457            matched = EGL_FALSE;
458         break;
459      case ATTRIB_CRITERION_SPECIAL:
460         /* ignored here */
461         break;
462      default:
463         assert(0);
464         break;
465      }
466
467      if (!matched) {
468#ifndef DEBUG
469         /* only print the common errors when DEBUG is not defined */
470         if (attr != EGL_RENDERABLE_TYPE)
471            break;
472#endif
473         _eglLog(_EGL_DEBUG,
474               "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
475               val, attr, cmp);
476         break;
477      }
478   }
479
480   return matched;
481}
482
483static INLINE EGLBoolean
484_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
485{
486   if (_eglOffsetOfConfig(attr) < 0)
487      return EGL_FALSE;
488
489   switch (attr) {
490   case EGL_Y_INVERTED_NOK:
491      return conf->Display->Extensions.NOK_texture_from_pixmap;
492   default:
493      break;
494   }
495
496   return EGL_TRUE;
497}
498
499/**
500 * Initialize a criteria config from the given attribute list.
501 * Return EGL_FALSE if any of the attribute is invalid.
502 */
503EGLBoolean
504_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
505                          const EGLint *attrib_list)
506{
507   EGLint attr, val, i;
508
509   _eglInitConfig(conf, dpy, EGL_DONT_CARE);
510
511   /* reset to default values */
512   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
513      attr = _eglValidationTable[i].attr;
514      val = _eglValidationTable[i].default_value;
515      _eglSetConfigKey(conf, attr, val);
516   }
517
518   /* parse the list */
519   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
520      attr = attrib_list[i];
521      val = attrib_list[i + 1];
522
523      if (!_eglIsConfigAttribValid(conf, attr))
524	 return EGL_FALSE;
525
526      _eglSetConfigKey(conf, attr, val);
527   }
528
529   if (!_eglValidateConfig(conf, EGL_TRUE))
530      return EGL_FALSE;
531
532   /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
533   if (conf->Level == EGL_DONT_CARE ||
534       conf->MatchNativePixmap == EGL_DONT_CARE)
535      return EGL_FALSE;
536
537   /* ignore other attributes when EGL_CONFIG_ID is given */
538   if (conf->ConfigID != EGL_DONT_CARE) {
539      for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
540         attr = _eglValidationTable[i].attr;
541         if (attr != EGL_CONFIG_ID)
542            _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
543      }
544   }
545   else {
546      if (!(conf->SurfaceType & EGL_WINDOW_BIT))
547         conf->NativeVisualType = EGL_DONT_CARE;
548
549      if (conf->TransparentType == EGL_NONE) {
550         conf->TransparentRedValue = EGL_DONT_CARE;
551         conf->TransparentGreenValue = EGL_DONT_CARE;
552         conf->TransparentBlueValue = EGL_DONT_CARE;
553      }
554   }
555
556   return EGL_TRUE;
557}
558
559
560/**
561 * Decide the ordering of conf1 and conf2, under the given criteria.
562 * When compare_id is true, this implements the algorithm described
563 * in "Sorting of EGLConfigs".  When compare_id is false,
564 * EGL_CONFIG_ID is not compared.
565 *
566 * It returns a negative integer if conf1 is considered to come
567 * before conf2;  a positive integer if conf2 is considered to come
568 * before conf1;  zero if the ordering cannot be decided.
569 *
570 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
571 * ignored here.
572 */
573EGLint
574_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
575                   const _EGLConfig *criteria, EGLBoolean compare_id)
576{
577   const EGLint compare_attribs[] = {
578      EGL_BUFFER_SIZE,
579      EGL_SAMPLE_BUFFERS,
580      EGL_SAMPLES,
581      EGL_DEPTH_SIZE,
582      EGL_STENCIL_SIZE,
583      EGL_ALPHA_MASK_SIZE,
584   };
585   EGLint val1, val2;
586   EGLint i;
587
588   if (conf1 == conf2)
589      return 0;
590
591   /* the enum values have the desired ordering */
592   assert(EGL_NONE < EGL_SLOW_CONFIG);
593   assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
594   val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
595   if (val1)
596      return val1;
597
598   /* the enum values have the desired ordering */
599   assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
600   val1 = conf1->ColorBufferType - conf2->ColorBufferType;
601   if (val1)
602      return val1;
603
604   if (criteria) {
605      val1 = val2 = 0;
606      if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
607         if (criteria->RedSize > 0) {
608            val1 += conf1->RedSize;
609            val2 += conf2->RedSize;
610         }
611         if (criteria->GreenSize > 0) {
612            val1 += conf1->GreenSize;
613            val2 += conf2->GreenSize;
614         }
615         if (criteria->BlueSize > 0) {
616            val1 += conf1->BlueSize;
617            val2 += conf2->BlueSize;
618         }
619      }
620      else {
621         if (criteria->LuminanceSize > 0) {
622            val1 += conf1->LuminanceSize;
623            val2 += conf2->LuminanceSize;
624         }
625      }
626      if (criteria->AlphaSize > 0) {
627         val1 += conf1->AlphaSize;
628         val2 += conf2->AlphaSize;
629      }
630   }
631   else {
632      /* assume the default criteria, which gives no specific ordering */
633      val1 = val2 = 0;
634   }
635
636   /* for color bits, larger one is preferred */
637   if (val1 != val2)
638      return (val2 - val1);
639
640   for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
641      val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
642      val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
643      if (val1 != val2)
644         return (val1 - val2);
645   }
646
647   /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
648
649   return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
650}
651
652
653static INLINE
654void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
655{
656   const _EGLConfig *tmp = *conf1;
657   *conf1 = *conf2;
658   *conf2 = tmp;
659}
660
661
662/**
663 * Quick sort an array of configs.  This differs from the standard
664 * qsort() in that the compare function accepts an additional
665 * argument.
666 */
667static void
668_eglSortConfigs(const _EGLConfig **configs, EGLint count,
669                EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
670                                  void *),
671                void *priv_data)
672{
673   const EGLint pivot = 0;
674   EGLint i, j;
675
676   if (count <= 1)
677      return;
678
679   _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
680   i = 1;
681   j = count - 1;
682   do {
683      while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
684         i++;
685      while (compare(configs[j], configs[pivot], priv_data) > 0)
686         j--;
687      if (i < j) {
688         _eglSwapConfigs(&configs[i], &configs[j]);
689         i++;
690         j--;
691      }
692      else if (i == j) {
693         i++;
694         j--;
695         break;
696      }
697   } while (i <= j);
698   _eglSwapConfigs(&configs[pivot], &configs[j]);
699
700   _eglSortConfigs(configs, j, compare, priv_data);
701   _eglSortConfigs(configs + i, count - i, compare, priv_data);
702}
703
704
705/**
706 * A helper function for implementing eglChooseConfig.  See _eglFilterArray and
707 * _eglSortConfigs for the meanings of match and compare.
708 */
709EGLBoolean
710_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
711                      EGLint config_size, EGLint *num_configs,
712                      EGLBoolean (*match)(const _EGLConfig *, void *),
713                      EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
714                                        void *),
715                      void *priv_data)
716{
717   _EGLConfig **configList;
718   EGLint i, count;
719
720   if (!num_configs)
721      return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
722
723   /* get the number of matched configs */
724   count = _eglFilterArray(array, NULL, 0,
725         (_EGLArrayForEach) match, priv_data);
726   if (!count) {
727      *num_configs = count;
728      return EGL_TRUE;
729   }
730
731   configList = malloc(sizeof(*configList) * count);
732   if (!configList)
733      return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
734
735   /* get the matched configs */
736   _eglFilterArray(array, (void **) configList, count,
737         (_EGLArrayForEach) match, priv_data);
738
739   /* perform sorting of configs */
740   if (configs && count) {
741      _eglSortConfigs((const _EGLConfig **) configList, count,
742                      compare, priv_data);
743      count = MIN2(count, config_size);
744      for (i = 0; i < count; i++)
745         configs[i] = _eglGetConfigHandle(configList[i]);
746   }
747
748   free(configList);
749
750   *num_configs = count;
751
752   return EGL_TRUE;
753}
754
755
756static EGLBoolean
757_eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
758{
759   return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
760}
761
762
763static EGLint
764_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
765                    void *priv_data)
766{
767   return _eglCompareConfigs(conf1, conf2,
768         (const _EGLConfig *) priv_data, EGL_TRUE);
769}
770
771
772/**
773 * Typical fallback routine for eglChooseConfig
774 */
775EGLBoolean
776_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
777                 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
778{
779   _EGLConfig criteria;
780
781   if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
782      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
783
784   return _eglFilterConfigArray(disp->Configs,
785         configs, config_size, num_configs,
786         _eglFallbackMatch, _eglFallbackCompare,
787         (void *) &criteria);
788}
789
790
791/**
792 * Fallback for eglGetConfigAttrib.
793 */
794EGLBoolean
795_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
796                    EGLint attribute, EGLint *value)
797{
798   if (!_eglIsConfigAttribValid(conf, attribute))
799      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
800
801   /* nonqueryable attributes */
802   switch (attribute) {
803   case EGL_MATCH_NATIVE_PIXMAP:
804      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
805      break;
806   default:
807      break;
808   }
809
810   if (!value)
811      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
812
813   *value = _eglGetConfigKey(conf, attribute);
814   return EGL_TRUE;
815}
816
817
818static EGLBoolean
819_eglFlattenConfig(void *elem, void *buffer)
820{
821   _EGLConfig *conf = (_EGLConfig *) elem;
822   EGLConfig *handle = (EGLConfig *) buffer;
823   *handle = _eglGetConfigHandle(conf);
824   return EGL_TRUE;
825}
826
827/**
828 * Fallback for eglGetConfigs.
829 */
830EGLBoolean
831_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
832               EGLint config_size, EGLint *num_config)
833{
834   if (!num_config)
835      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
836
837   *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
838         sizeof(configs[0]), config_size, _eglFlattenConfig);
839
840   return EGL_TRUE;
841}
842