eglconfig.c revision 554e4fc26a64a90012b0d7dcc1205441273f214c
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
481static INLINE EGLBoolean
482_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
483{
484   if (_eglIndexConfig(conf, attr) < 0)
485      return EGL_FALSE;
486
487   /* there are some holes in the range */
488   switch (attr) {
489   case 0x3030 /* a gap before EGL_SAMPLES */:
490   case EGL_NONE:
491#ifdef EGL_VERSION_1_4
492   case EGL_MATCH_NATIVE_PIXMAP:
493#endif
494      return EGL_FALSE;
495   default:
496      break;
497   }
498
499   return EGL_TRUE;
500}
501
502/**
503 * Initialize a criteria config from the given attribute list.
504 * Return EGL_FALSE if any of the attribute is invalid.
505 */
506EGLBoolean
507_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
508{
509   EGLint attr, val, i;
510   EGLint config_id = 0, level = 0;
511   EGLBoolean has_native_visual_type = EGL_FALSE;
512   EGLBoolean has_transparent_color = EGL_FALSE;
513
514   /* reset to default values */
515   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
516      attr = _eglValidationTable[i].attr;
517      val = _eglValidationTable[i].default_value;
518      SET_CONFIG_ATTRIB(conf, attr, val);
519   }
520
521   /* parse the list */
522   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
523      attr = attrib_list[i];
524      val = attrib_list[i + 1];
525
526      if (!_eglIsConfigAttribValid(conf, attr))
527	 return EGL_FALSE;
528
529      SET_CONFIG_ATTRIB(conf, attr, val);
530
531      /* rememeber some attributes for post-processing */
532      switch (attr) {
533      case EGL_CONFIG_ID:
534         config_id = val;
535         break;
536      case EGL_LEVEL:
537         level = val;
538         break;
539      case EGL_NATIVE_VISUAL_TYPE:
540         has_native_visual_type = EGL_TRUE;
541         break;
542      case EGL_TRANSPARENT_RED_VALUE:
543      case EGL_TRANSPARENT_GREEN_VALUE:
544      case EGL_TRANSPARENT_BLUE_VALUE:
545         has_transparent_color = EGL_TRUE;
546         break;
547      default:
548         break;
549      }
550   }
551
552   if (!_eglValidateConfig(conf, EGL_TRUE))
553      return EGL_FALSE;
554
555   /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
556   if (level == EGL_DONT_CARE)
557      return EGL_FALSE;
558
559   /* ignore other attributes when EGL_CONFIG_ID is given */
560   if (config_id > 0) {
561      _eglResetConfigKeys(conf, EGL_DONT_CARE);
562      SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id);
563   }
564   else {
565      if (has_native_visual_type) {
566         val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
567         if (!(val & EGL_WINDOW_BIT))
568            SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
569      }
570
571      if (has_transparent_color) {
572         val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE);
573         if (val == EGL_NONE) {
574            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE,
575                              EGL_DONT_CARE);
576            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE,
577                              EGL_DONT_CARE);
578            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE,
579                              EGL_DONT_CARE);
580         }
581      }
582   }
583
584   return EGL_TRUE;
585}
586
587
588/**
589 * Decide the ordering of conf1 and conf2, under the given criteria.
590 * When compare_id is true, this implements the algorithm described
591 * in "Sorting of EGLConfigs".  When compare_id is false,
592 * EGL_CONFIG_ID is not compared.
593 *
594 * It returns a negative integer if conf1 is considered to come
595 * before conf2;  a positive integer if conf2 is considered to come
596 * before conf1;  zero if the ordering cannot be decided.
597 *
598 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
599 * ignored here.
600 */
601EGLint
602_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
603                   const _EGLConfig *criteria, EGLBoolean compare_id)
604{
605   const EGLint compare_attribs[] = {
606      EGL_BUFFER_SIZE,
607      EGL_SAMPLE_BUFFERS,
608      EGL_SAMPLES,
609      EGL_DEPTH_SIZE,
610      EGL_STENCIL_SIZE,
611      EGL_ALPHA_MASK_SIZE,
612   };
613   EGLint val1, val2;
614   EGLBoolean rgb_buffer;
615   EGLint i;
616
617   if (conf1 == conf2)
618      return 0;
619
620   /* the enum values have the desired ordering */
621   assert(EGL_NONE < EGL_SLOW_CONFIG);
622   assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
623   val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT);
624   val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT);
625   if (val1 != val2)
626      return (val1 - val2);
627
628   /* the enum values have the desired ordering */
629   assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
630   val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE);
631   val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE);
632   if (val1 != val2)
633      return (val1 - val2);
634   rgb_buffer = (val1 == EGL_RGB_BUFFER);
635
636   if (criteria) {
637      val1 = val2 = 0;
638      if (rgb_buffer) {
639         if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) {
640            val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE);
641            val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE);
642         }
643         if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) {
644            val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE);
645            val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE);
646         }
647         if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) {
648            val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE);
649            val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE);
650         }
651      }
652      else {
653         if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) {
654            val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE);
655            val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE);
656         }
657      }
658      if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) {
659         val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE);
660         val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE);
661      }
662   }
663   else {
664      /* assume the default criteria, which gives no specific ordering */
665      val1 = val2 = 0;
666   }
667
668   /* for color bits, larger one is preferred */
669   if (val1 != val2)
670      return (val2 - val1);
671
672   for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
673      val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]);
674      val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]);
675      if (val1 != val2)
676         return (val1 - val2);
677   }
678
679   /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
680
681   if (compare_id) {
682      val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID);
683      val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID);
684      assert(val1 != val2);
685   }
686   else {
687      val1 = val2 = 0;
688   }
689
690   return (val1 - val2);
691}
692
693
694static INLINE
695void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
696{
697   const _EGLConfig *tmp = *conf1;
698   *conf1 = *conf2;
699   *conf2 = tmp;
700}
701
702
703/**
704 * Quick sort an array of configs.  This differs from the standard
705 * qsort() in that the compare function accepts an additional
706 * argument.
707 */
708void
709_eglSortConfigs(const _EGLConfig **configs, EGLint count,
710                EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
711                                  void *),
712                void *priv_data)
713{
714   const EGLint pivot = 0;
715   EGLint i, j;
716
717   if (count <= 1)
718      return;
719
720   _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
721   i = 1;
722   j = count - 1;
723   do {
724      while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
725         i++;
726      while (compare(configs[j], configs[pivot], priv_data) > 0)
727         j--;
728      if (i < j) {
729         _eglSwapConfigs(&configs[i], &configs[j]);
730         i++;
731         j--;
732      }
733      else if (i == j) {
734         i++;
735         j--;
736         break;
737      }
738   } while (i <= j);
739   _eglSwapConfigs(&configs[pivot], &configs[j]);
740
741   _eglSortConfigs(configs, j, compare, priv_data);
742   _eglSortConfigs(configs + i, count - i, compare, priv_data);
743}
744
745
746static int
747_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
748                   void *priv_data)
749{
750   const _EGLConfig *criteria = (const _EGLConfig *) priv_data;
751   return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
752}
753
754
755/**
756 * Typical fallback routine for eglChooseConfig
757 */
758EGLBoolean
759_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
760                 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
761{
762   _EGLConfig **configList, criteria;
763   EGLint i, count;
764
765   if (!num_configs)
766      return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
767
768   _eglInitConfig(&criteria, disp, 0);
769   if (!_eglParseConfigAttribList(&criteria, attrib_list))
770      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
771
772   /* allocate array of config pointers */
773   configList = (_EGLConfig **)
774      malloc(disp->NumConfigs * sizeof(_EGLConfig *));
775   if (!configList)
776      return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
777
778   /* perform selection of configs */
779   count = 0;
780   for (i = 0; i < disp->NumConfigs; i++) {
781      if (_eglMatchConfig(disp->Configs[i], &criteria))
782         configList[count++] = disp->Configs[i];
783   }
784
785   /* perform sorting of configs */
786   if (configs && count) {
787      _eglSortConfigs((const _EGLConfig **) configList, count,
788                      _eglFallbackCompare, (void *) &criteria);
789      count = MIN2(count, config_size);
790      for (i = 0; i < count; i++)
791         configs[i] = _eglGetConfigHandle(configList[i]);
792   }
793
794   free(configList);
795
796   *num_configs = count;
797
798   return EGL_TRUE;
799}
800
801
802/**
803 * Fallback for eglGetConfigAttrib.
804 */
805EGLBoolean
806_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
807                    EGLint attribute, EGLint *value)
808{
809   if (!_eglIsConfigAttribValid(conf, attribute))
810      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
811   if (!value)
812      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
813
814   *value = GET_CONFIG_ATTRIB(conf, attribute);
815   return EGL_TRUE;
816}
817
818
819/**
820 * Fallback for eglGetConfigs.
821 */
822EGLBoolean
823_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
824               EGLint config_size, EGLint *num_config)
825{
826   if (!num_config)
827      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
828
829   if (configs) {
830      EGLint i;
831      *num_config = MIN2(disp->NumConfigs, config_size);
832      for (i = 0; i < *num_config; i++)
833         configs[i] = _eglGetConfigHandle(disp->Configs[i]);
834   }
835   else {
836      /* just return total number of supported configs */
837      *num_config = disp->NumConfigs;
838   }
839
840   return EGL_TRUE;
841}
842