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