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