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