eglconfig.c revision 216925ccd122a06505dafae425323e3ac858f80e
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#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
17
18
19/**
20 * Init the given _EGLconfig to default values.
21 * \param id  the configuration's ID.
22 *
23 * Note that id must be positive for the config to be valid.
24 * It is also recommended that when there are N configs, their
25 * IDs are from 1 to N respectively.
26 */
27void
28_eglInitConfig(_EGLConfig *config, _EGLDisplay *dpy, EGLint id)
29{
30   memset(config, 0, sizeof(*config));
31
32   config->Display = dpy;
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   /* there is a gap before EGL_SAMPLES */
228   { 0x3030,                        ATTRIB_TYPE_PSEUDO,
229                                    ATTRIB_CRITERION_IGNORE,
230                                    0 },
231   { EGL_NONE,                      ATTRIB_TYPE_PSEUDO,
232                                    ATTRIB_CRITERION_IGNORE,
233                                    0 }
234};
235
236
237/**
238 * Return true if a config is valid.  When for_matching is true,
239 * EGL_DONT_CARE is accepted as a valid attribute value, and checks
240 * for conflicting attribute values are skipped.
241 *
242 * Note that some attributes are platform-dependent and are not
243 * checked.
244 */
245EGLBoolean
246_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
247{
248   EGLint i, attr, val;
249   EGLBoolean valid = EGL_TRUE;
250   EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0;
251   EGLint alpha_size = 0, buffer_size = 0;
252
253   /* all attributes should have been listed */
254   assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS);
255
256   /* check attributes by their types */
257   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
258      EGLint mask;
259
260      attr = _eglValidationTable[i].attr;
261      val = GET_CONFIG_ATTRIB(conf, attr);
262
263      switch (_eglValidationTable[i].type) {
264      case ATTRIB_TYPE_INTEGER:
265         switch (attr) {
266         case EGL_CONFIG_ID:
267            /* config id must be positive */
268            if (val <= 0)
269               valid = EGL_FALSE;
270            break;
271         case EGL_SAMPLE_BUFFERS:
272            /* there can be at most 1 sample buffer */
273            if (val > 1)
274               valid = EGL_FALSE;
275            break;
276         case EGL_RED_SIZE:
277            red_size = val;
278            break;
279         case EGL_GREEN_SIZE:
280            green_size = val;
281            break;
282         case EGL_BLUE_SIZE:
283            blue_size = val;
284            break;
285         case EGL_LUMINANCE_SIZE:
286            luminance_size = val;
287            break;
288         case EGL_ALPHA_SIZE:
289            alpha_size = val;
290            break;
291         case EGL_BUFFER_SIZE:
292            buffer_size = val;
293            break;
294         }
295         if (val < 0)
296            valid = EGL_FALSE;
297         break;
298      case ATTRIB_TYPE_BOOLEAN:
299         if (val != EGL_TRUE && val != EGL_FALSE)
300            valid = EGL_FALSE;
301         break;
302      case ATTRIB_TYPE_ENUM:
303         switch (attr) {
304         case EGL_CONFIG_CAVEAT:
305            if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
306                val != EGL_NON_CONFORMANT_CONFIG)
307               valid = EGL_FALSE;
308            break;
309         case EGL_TRANSPARENT_TYPE:
310            if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
311               valid = EGL_FALSE;
312            break;
313         case EGL_COLOR_BUFFER_TYPE:
314            if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
315               valid = EGL_FALSE;
316            break;
317         default:
318            assert(0);
319            break;
320         }
321         break;
322      case ATTRIB_TYPE_BITMASK:
323         switch (attr) {
324         case EGL_SURFACE_TYPE:
325            mask = EGL_PBUFFER_BIT |
326                   EGL_PIXMAP_BIT |
327                   EGL_WINDOW_BIT |
328                   EGL_SCREEN_BIT_MESA | /* XXX should check the extension */
329                   EGL_VG_COLORSPACE_LINEAR_BIT |
330                   EGL_VG_ALPHA_FORMAT_PRE_BIT |
331                   EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
332                   EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
333            break;
334         case EGL_RENDERABLE_TYPE:
335         case EGL_CONFORMANT:
336            mask = EGL_OPENGL_ES_BIT |
337                   EGL_OPENVG_BIT |
338                   EGL_OPENGL_ES2_BIT |
339                   EGL_OPENGL_BIT;
340            break;
341         default:
342            assert(0);
343            break;
344         }
345         if (val & ~mask)
346            valid = EGL_FALSE;
347         break;
348      case ATTRIB_TYPE_PLATFORM:
349         /* unable to check platform-dependent attributes here */
350         break;
351      case ATTRIB_TYPE_PSEUDO:
352         /* pseudo attributes should not be set */
353         if (val != 0)
354            valid = EGL_FALSE;
355         break;
356      default:
357         assert(0);
358         break;
359      }
360
361      if (!valid && for_matching) {
362         /* accept EGL_DONT_CARE as a valid value */
363         if (val == EGL_DONT_CARE)
364            valid = EGL_TRUE;
365         if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
366            valid = EGL_TRUE;
367      }
368      if (!valid)
369         break;
370   }
371
372   /* any invalid attribute value should have been catched */
373   if (!valid || for_matching)
374      return valid;
375
376   /* now check for conflicting attribute values */
377
378   switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) {
379   case EGL_RGB_BUFFER:
380      if (luminance_size)
381         valid = EGL_FALSE;
382      if (red_size + green_size + blue_size + alpha_size != buffer_size)
383         valid = EGL_FALSE;
384      break;
385   case EGL_LUMINANCE_BUFFER:
386      if (red_size || green_size || blue_size)
387         valid = EGL_FALSE;
388      if (luminance_size + alpha_size != buffer_size)
389         valid = EGL_FALSE;
390      break;
391   }
392
393   val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS);
394   if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES))
395      valid = EGL_FALSE;
396
397   val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
398   if (!(val & EGL_WINDOW_BIT)) {
399      if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 ||
400          GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE)
401         valid = EGL_FALSE;
402   }
403   if (!(val & EGL_PBUFFER_BIT)) {
404      if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) ||
405          GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA))
406         valid = EGL_FALSE;
407   }
408
409   return valid;
410}
411
412
413/**
414 * Return true if a config matches the criteria.  This and
415 * _eglParseConfigAttribList together implement the algorithm
416 * described in "Selection of EGLConfigs".
417 *
418 * Note that attributes that are special (currently, only
419 * EGL_MATCH_NATIVE_PIXMAP) are ignored.
420 */
421EGLBoolean
422_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
423{
424   EGLint attr, val, i;
425   EGLBoolean matched = EGL_TRUE;
426
427   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
428      EGLint cmp;
429      if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
430         continue;
431
432      attr = _eglValidationTable[i].attr;
433      cmp = GET_CONFIG_ATTRIB(criteria, attr);
434      if (cmp == EGL_DONT_CARE)
435         continue;
436
437      val = GET_CONFIG_ATTRIB(conf, attr);
438      switch (_eglValidationTable[i].criterion) {
439      case ATTRIB_CRITERION_EXACT:
440         if (val != cmp)
441            matched = EGL_FALSE;
442         break;
443      case ATTRIB_CRITERION_ATLEAST:
444         if (val < cmp)
445            matched = EGL_FALSE;
446         break;
447      case ATTRIB_CRITERION_MASK:
448         if ((val & cmp) != cmp)
449            matched = EGL_FALSE;
450         break;
451      case ATTRIB_CRITERION_SPECIAL:
452         /* ignored here */
453         break;
454      default:
455         assert(0);
456         break;
457      }
458
459      if (!matched)
460         break;
461   }
462
463   return matched;
464}
465
466
467/**
468 * Initialize a criteria config from the given attribute list.
469 * Return EGL_FALSE if any of the attribute is invalid.
470 */
471EGLBoolean
472_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list)
473{
474   EGLint attr, val, i;
475   EGLint config_id = 0, level = 0;
476   EGLBoolean has_native_visual_type = EGL_FALSE;
477   EGLBoolean has_transparent_color = EGL_FALSE;
478
479   /* reset to default values */
480   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
481      attr = _eglValidationTable[i].attr;
482      val = _eglValidationTable[i].default_value;
483      SET_CONFIG_ATTRIB(conf, attr, val);
484   }
485
486   /* parse the list */
487   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
488      EGLint idx;
489
490      attr = attrib_list[i];
491      val = attrib_list[i + 1];
492
493      idx = _eglIndexConfig(conf, attr);
494      if (idx < 0)
495         return EGL_FALSE;
496      conf->Storage[idx] = val;
497
498      /* rememeber some attributes for post-processing */
499      switch (attr) {
500      case EGL_CONFIG_ID:
501         config_id = val;
502         break;
503      case EGL_LEVEL:
504         level = val;
505         break;
506      case EGL_NATIVE_VISUAL_TYPE:
507         has_native_visual_type = EGL_TRUE;
508         break;
509      case EGL_TRANSPARENT_RED_VALUE:
510      case EGL_TRANSPARENT_GREEN_VALUE:
511      case EGL_TRANSPARENT_BLUE_VALUE:
512         has_transparent_color = EGL_TRUE;
513         break;
514      default:
515         break;
516      }
517   }
518
519   if (!_eglValidateConfig(conf, EGL_TRUE))
520      return EGL_FALSE;
521
522   /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
523   if (level == EGL_DONT_CARE)
524      return EGL_FALSE;
525
526   /* ignore other attributes when EGL_CONFIG_ID is given */
527   if (config_id > 0) {
528      _eglResetConfigKeys(conf, EGL_DONT_CARE);
529      SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id);
530   }
531   else {
532      if (has_native_visual_type) {
533         val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE);
534         if (!(val & EGL_WINDOW_BIT))
535            SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
536      }
537
538      if (has_transparent_color) {
539         val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE);
540         if (val == EGL_NONE) {
541            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE,
542                              EGL_DONT_CARE);
543            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE,
544                              EGL_DONT_CARE);
545            SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE,
546                              EGL_DONT_CARE);
547         }
548      }
549   }
550
551   return EGL_TRUE;
552}
553
554
555/**
556 * Decide the ordering of conf1 and conf2, under the given criteria.
557 * When compare_id is true, this implements the algorithm described
558 * in "Sorting of EGLConfigs".  When compare_id is false,
559 * EGL_CONFIG_ID is not compared.
560 *
561 * It returns a negative integer if conf1 is considered to come
562 * before conf2;  a positive integer if conf2 is considered to come
563 * before conf1;  zero if the ordering cannot be decided.
564 *
565 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
566 * ignored here.
567 */
568EGLint
569_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
570                   const _EGLConfig *criteria, EGLBoolean compare_id)
571{
572   const EGLint compare_attribs[] = {
573      EGL_BUFFER_SIZE,
574      EGL_SAMPLE_BUFFERS,
575      EGL_SAMPLES,
576      EGL_DEPTH_SIZE,
577      EGL_STENCIL_SIZE,
578      EGL_ALPHA_MASK_SIZE,
579   };
580   EGLint val1, val2;
581   EGLBoolean rgb_buffer;
582   EGLint i;
583
584   if (conf1 == conf2)
585      return 0;
586
587   /* the enum values have the desired ordering */
588   assert(EGL_NONE < EGL_SLOW_CONFIG);
589   assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
590   val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT);
591   val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT);
592   if (val1 != val2)
593      return (val1 - val2);
594
595   /* the enum values have the desired ordering */
596   assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
597   val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE);
598   val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE);
599   if (val1 != val2)
600      return (val1 - val2);
601   rgb_buffer = (val1 == EGL_RGB_BUFFER);
602
603   if (criteria) {
604      val1 = val2 = 0;
605      if (rgb_buffer) {
606         if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) {
607            val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE);
608            val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE);
609         }
610         if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) {
611            val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE);
612            val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE);
613         }
614         if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) {
615            val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE);
616            val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE);
617         }
618      }
619      else {
620         if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) {
621            val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE);
622            val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE);
623         }
624      }
625      if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) {
626         val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE);
627         val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE);
628      }
629   }
630   else {
631      /* assume the default criteria, which gives no specific ordering */
632      val1 = val2 = 0;
633   }
634
635   /* for color bits, larger one is preferred */
636   if (val1 != val2)
637      return (val2 - val1);
638
639   for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
640      val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]);
641      val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]);
642      if (val1 != val2)
643         return (val1 - val2);
644   }
645
646   /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
647
648   if (compare_id) {
649      val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID);
650      val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID);
651      assert(val1 != val2);
652   }
653   else {
654      val1 = val2 = 0;
655   }
656
657   return (val1 - val2);
658}
659
660
661static INLINE
662void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
663{
664   const _EGLConfig *tmp = *conf1;
665   *conf1 = *conf2;
666   *conf2 = tmp;
667}
668
669
670/**
671 * Quick sort an array of configs.  This differs from the standard
672 * qsort() in that the compare function accepts an additional
673 * argument.
674 */
675void
676_eglSortConfigs(const _EGLConfig **configs, EGLint count,
677                EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
678                                  void *),
679                void *priv_data)
680{
681   const EGLint pivot = 0;
682   EGLint i, j;
683
684   if (count <= 1)
685      return;
686
687   _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
688   i = 1;
689   j = count - 1;
690   do {
691      while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
692         i++;
693      while (compare(configs[j], configs[pivot], priv_data) > 0)
694         j--;
695      if (i < j) {
696         _eglSwapConfigs(&configs[i], &configs[j]);
697         i++;
698         j--;
699      }
700      else if (i == j) {
701         i++;
702         j--;
703         break;
704      }
705   } while (i <= j);
706   _eglSwapConfigs(&configs[pivot], &configs[j]);
707
708   _eglSortConfigs(configs, j, compare, priv_data);
709   _eglSortConfigs(configs + i, count - i, compare, priv_data);
710}
711
712
713static int
714_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
715                   void *priv_data)
716{
717   const _EGLConfig *criteria = (const _EGLConfig *) priv_data;
718   return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
719}
720
721
722/**
723 * Typical fallback routine for eglChooseConfig
724 */
725EGLBoolean
726_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
727                 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
728{
729   _EGLConfig **configList, criteria;
730   EGLint i, count;
731
732   if (!num_configs)
733      return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
734
735   _eglInitConfig(&criteria, disp, 0);
736   if (!_eglParseConfigAttribList(&criteria, attrib_list))
737      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
738
739   /* allocate array of config pointers */
740   configList = (_EGLConfig **)
741      malloc(disp->NumConfigs * sizeof(_EGLConfig *));
742   if (!configList)
743      return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
744
745   /* perform selection of configs */
746   count = 0;
747   for (i = 0; i < disp->NumConfigs; i++) {
748      if (_eglMatchConfig(disp->Configs[i], &criteria))
749         configList[count++] = disp->Configs[i];
750   }
751
752   /* perform sorting of configs */
753   if (configs && count) {
754      _eglSortConfigs((const _EGLConfig **) configList, count,
755                      _eglFallbackCompare, (void *) &criteria);
756      count = MIN2(count, config_size);
757      for (i = 0; i < count; i++)
758         configs[i] = _eglGetConfigHandle(configList[i]);
759   }
760
761   free(configList);
762
763   *num_configs = count;
764
765   return EGL_TRUE;
766}
767
768
769static INLINE EGLBoolean
770_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
771{
772   if (_eglIndexConfig(conf, attr) < 0)
773      return EGL_FALSE;
774
775   /* there are some holes in the range */
776   switch (attr) {
777   case 0x3030 /* a gap before EGL_SAMPLES */:
778   case EGL_NONE:
779#ifdef EGL_VERSION_1_4
780   case EGL_MATCH_NATIVE_PIXMAP:
781#endif
782      return EGL_FALSE;
783   default:
784      break;
785   }
786
787   return EGL_TRUE;
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   if (!value)
801      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
802
803   *value = GET_CONFIG_ATTRIB(conf, attribute);
804   return EGL_TRUE;
805}
806
807
808/**
809 * Fallback for eglGetConfigs.
810 */
811EGLBoolean
812_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
813               EGLint config_size, EGLint *num_config)
814{
815   if (!num_config)
816      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
817
818   if (configs) {
819      EGLint i;
820      *num_config = MIN2(disp->NumConfigs, config_size);
821      for (i = 0; i < *num_config; i++)
822         configs[i] = _eglGetConfigHandle(disp->Configs[i]);
823   }
824   else {
825      /* just return total number of supported configs */
826      *num_config = disp->NumConfigs;
827   }
828
829   return EGL_TRUE;
830}
831