eglconfig.c revision af69d88d
1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sub license, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
18 * of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 *
28 **************************************************************************/
29
30
31/**
32 * EGL Configuration (pixel format) functions.
33 */
34
35
36#include <stdlib.h>
37#include <string.h>
38#include <assert.h>
39#include "eglconfig.h"
40#include "egldisplay.h"
41#include "eglcurrent.h"
42#include "egllog.h"
43
44
45#define MIN2(A, B)  (((A) < (B)) ? (A) : (B))
46
47
48/**
49 * Init the given _EGLconfig to default values.
50 * \param id  the configuration's ID.
51 *
52 * Note that id must be positive for the config to be valid.
53 * It is also recommended that when there are N configs, their
54 * IDs are from 1 to N respectively.
55 */
56void
57_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
58{
59   memset(conf, 0, sizeof(*conf));
60
61   conf->Display = dpy;
62
63   /* some attributes take non-zero default values */
64   conf->ConfigID = id;
65   conf->ConfigCaveat = EGL_NONE;
66   conf->TransparentType = EGL_NONE;
67   conf->NativeVisualType = EGL_NONE;
68   conf->ColorBufferType = EGL_RGB_BUFFER;
69}
70
71
72/**
73 * Link a config to its display and return the handle of the link.
74 * The handle can be passed to client directly.
75 *
76 * Note that we just save the ptr to the config (we don't copy the config).
77 */
78PUBLIC EGLConfig
79_eglLinkConfig(_EGLConfig *conf)
80{
81   _EGLDisplay *dpy = conf->Display;
82
83   /* sanity check */
84   assert(dpy && conf->ConfigID > 0);
85
86   if (!dpy->Configs) {
87      dpy->Configs = _eglCreateArray("Config", 16);
88      if (!dpy->Configs)
89         return (EGLConfig) NULL;
90   }
91
92   _eglAppendArray(dpy->Configs, (void *) conf);
93
94   return (EGLConfig) conf;
95}
96
97
98/**
99 * Lookup a handle to find the linked config.
100 * Return NULL if the handle has no corresponding linked config.
101 */
102_EGLConfig *
103_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
104{
105   _EGLConfig *conf;
106
107   if (!dpy)
108      return NULL;
109
110   conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
111   if (conf)
112      assert(conf->Display == dpy);
113
114   return conf;
115}
116
117
118enum {
119   /* types */
120   ATTRIB_TYPE_INTEGER,
121   ATTRIB_TYPE_BOOLEAN,
122   ATTRIB_TYPE_BITMASK,
123   ATTRIB_TYPE_ENUM,
124   ATTRIB_TYPE_PSEUDO, /* non-queryable */
125   ATTRIB_TYPE_PLATFORM, /* platform-dependent */
126   /* criteria */
127   ATTRIB_CRITERION_EXACT,
128   ATTRIB_CRITERION_ATLEAST,
129   ATTRIB_CRITERION_MASK,
130   ATTRIB_CRITERION_SPECIAL,
131   ATTRIB_CRITERION_IGNORE
132};
133
134
135/* EGL spec Table 3.1 and 3.4 */
136static const struct {
137   EGLint attr;
138   EGLint type;
139   EGLint criterion;
140   EGLint default_value;
141} _eglValidationTable[] =
142{
143   /* core */
144   { EGL_BUFFER_SIZE,               ATTRIB_TYPE_INTEGER,
145                                    ATTRIB_CRITERION_ATLEAST,
146                                    0 },
147   { EGL_RED_SIZE,                  ATTRIB_TYPE_INTEGER,
148                                    ATTRIB_CRITERION_ATLEAST,
149                                    0 },
150   { EGL_GREEN_SIZE,                ATTRIB_TYPE_INTEGER,
151                                    ATTRIB_CRITERION_ATLEAST,
152                                    0 },
153   { EGL_BLUE_SIZE,                 ATTRIB_TYPE_INTEGER,
154                                    ATTRIB_CRITERION_ATLEAST,
155                                    0 },
156   { EGL_LUMINANCE_SIZE,            ATTRIB_TYPE_INTEGER,
157                                    ATTRIB_CRITERION_ATLEAST,
158                                    0 },
159   { EGL_ALPHA_SIZE,                ATTRIB_TYPE_INTEGER,
160                                    ATTRIB_CRITERION_ATLEAST,
161                                    0 },
162   { EGL_ALPHA_MASK_SIZE,           ATTRIB_TYPE_INTEGER,
163                                    ATTRIB_CRITERION_ATLEAST,
164                                    0 },
165   { EGL_BIND_TO_TEXTURE_RGB,       ATTRIB_TYPE_BOOLEAN,
166                                    ATTRIB_CRITERION_EXACT,
167                                    EGL_DONT_CARE },
168   { EGL_BIND_TO_TEXTURE_RGBA,      ATTRIB_TYPE_BOOLEAN,
169                                    ATTRIB_CRITERION_EXACT,
170                                    EGL_DONT_CARE },
171   { EGL_COLOR_BUFFER_TYPE,         ATTRIB_TYPE_ENUM,
172                                    ATTRIB_CRITERION_EXACT,
173                                    EGL_RGB_BUFFER },
174   { EGL_CONFIG_CAVEAT,             ATTRIB_TYPE_ENUM,
175                                    ATTRIB_CRITERION_EXACT,
176                                    EGL_DONT_CARE },
177   { EGL_CONFIG_ID,                 ATTRIB_TYPE_INTEGER,
178                                    ATTRIB_CRITERION_EXACT,
179                                    EGL_DONT_CARE },
180   { EGL_CONFORMANT,                ATTRIB_TYPE_BITMASK,
181                                    ATTRIB_CRITERION_MASK,
182                                    0 },
183   { EGL_DEPTH_SIZE,                ATTRIB_TYPE_INTEGER,
184                                    ATTRIB_CRITERION_ATLEAST,
185                                    0 },
186   { EGL_LEVEL,                     ATTRIB_TYPE_PLATFORM,
187                                    ATTRIB_CRITERION_EXACT,
188                                    0 },
189   { EGL_MAX_PBUFFER_WIDTH,         ATTRIB_TYPE_INTEGER,
190                                    ATTRIB_CRITERION_IGNORE,
191                                    0 },
192   { EGL_MAX_PBUFFER_HEIGHT,        ATTRIB_TYPE_INTEGER,
193                                    ATTRIB_CRITERION_IGNORE,
194                                    0 },
195   { EGL_MAX_PBUFFER_PIXELS,        ATTRIB_TYPE_INTEGER,
196                                    ATTRIB_CRITERION_IGNORE,
197                                    0 },
198   { EGL_MAX_SWAP_INTERVAL,         ATTRIB_TYPE_INTEGER,
199                                    ATTRIB_CRITERION_EXACT,
200                                    EGL_DONT_CARE },
201   { EGL_MIN_SWAP_INTERVAL,         ATTRIB_TYPE_INTEGER,
202                                    ATTRIB_CRITERION_EXACT,
203                                    EGL_DONT_CARE },
204   { EGL_NATIVE_RENDERABLE,         ATTRIB_TYPE_BOOLEAN,
205                                    ATTRIB_CRITERION_EXACT,
206                                    EGL_DONT_CARE },
207   { EGL_NATIVE_VISUAL_ID,          ATTRIB_TYPE_PLATFORM,
208                                    ATTRIB_CRITERION_IGNORE,
209                                    0 },
210   { EGL_NATIVE_VISUAL_TYPE,        ATTRIB_TYPE_PLATFORM,
211                                    ATTRIB_CRITERION_EXACT,
212                                    EGL_DONT_CARE },
213   { EGL_RENDERABLE_TYPE,           ATTRIB_TYPE_BITMASK,
214                                    ATTRIB_CRITERION_MASK,
215                                    EGL_OPENGL_ES_BIT },
216   { EGL_SAMPLE_BUFFERS,            ATTRIB_TYPE_INTEGER,
217                                    ATTRIB_CRITERION_ATLEAST,
218                                    0 },
219   { EGL_SAMPLES,                   ATTRIB_TYPE_INTEGER,
220                                    ATTRIB_CRITERION_ATLEAST,
221                                    0 },
222   { EGL_STENCIL_SIZE,              ATTRIB_TYPE_INTEGER,
223                                    ATTRIB_CRITERION_ATLEAST,
224                                    0 },
225   { EGL_SURFACE_TYPE,              ATTRIB_TYPE_BITMASK,
226                                    ATTRIB_CRITERION_MASK,
227                                    EGL_WINDOW_BIT },
228   { EGL_TRANSPARENT_TYPE,          ATTRIB_TYPE_ENUM,
229                                    ATTRIB_CRITERION_EXACT,
230                                    EGL_NONE },
231   { EGL_TRANSPARENT_RED_VALUE,     ATTRIB_TYPE_INTEGER,
232                                    ATTRIB_CRITERION_EXACT,
233                                    EGL_DONT_CARE },
234   { EGL_TRANSPARENT_GREEN_VALUE,   ATTRIB_TYPE_INTEGER,
235                                    ATTRIB_CRITERION_EXACT,
236                                    EGL_DONT_CARE },
237   { EGL_TRANSPARENT_BLUE_VALUE,    ATTRIB_TYPE_INTEGER,
238                                    ATTRIB_CRITERION_EXACT,
239                                    EGL_DONT_CARE },
240   { EGL_MATCH_NATIVE_PIXMAP,       ATTRIB_TYPE_PSEUDO,
241                                    ATTRIB_CRITERION_SPECIAL,
242                                    EGL_NONE },
243   /* extensions */
244   { EGL_Y_INVERTED_NOK,            ATTRIB_TYPE_BOOLEAN,
245                                    ATTRIB_CRITERION_EXACT,
246                                    EGL_DONT_CARE }
247};
248
249
250/**
251 * Return true if a config is valid.  When for_matching is true,
252 * EGL_DONT_CARE is accepted as a valid attribute value, and checks
253 * for conflicting attribute values are skipped.
254 *
255 * Note that some attributes are platform-dependent and are not
256 * checked.
257 */
258EGLBoolean
259_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
260{
261   EGLint i, attr, val;
262   EGLBoolean valid = EGL_TRUE;
263
264   /* check attributes by their types */
265   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
266      EGLint mask;
267
268      attr = _eglValidationTable[i].attr;
269      val = _eglGetConfigKey(conf, attr);
270
271      switch (_eglValidationTable[i].type) {
272      case ATTRIB_TYPE_INTEGER:
273         switch (attr) {
274         case EGL_CONFIG_ID:
275            /* config id must be positive */
276            if (val <= 0)
277               valid = EGL_FALSE;
278            break;
279         case EGL_SAMPLE_BUFFERS:
280            /* there can be at most 1 sample buffer */
281            if (val > 1 || val < 0)
282               valid = EGL_FALSE;
283            break;
284         default:
285            if (val < 0)
286               valid = EGL_FALSE;
287            break;
288         }
289         break;
290      case ATTRIB_TYPE_BOOLEAN:
291         if (val != EGL_TRUE && val != EGL_FALSE)
292            valid = EGL_FALSE;
293         break;
294      case ATTRIB_TYPE_ENUM:
295         switch (attr) {
296         case EGL_CONFIG_CAVEAT:
297            if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
298                val != EGL_NON_CONFORMANT_CONFIG)
299               valid = EGL_FALSE;
300            break;
301         case EGL_TRANSPARENT_TYPE:
302            if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
303               valid = EGL_FALSE;
304            break;
305         case EGL_COLOR_BUFFER_TYPE:
306            if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
307               valid = EGL_FALSE;
308            break;
309         default:
310            assert(0);
311            break;
312         }
313         break;
314      case ATTRIB_TYPE_BITMASK:
315         switch (attr) {
316         case EGL_SURFACE_TYPE:
317            mask = EGL_PBUFFER_BIT |
318                   EGL_PIXMAP_BIT |
319                   EGL_WINDOW_BIT |
320                   EGL_VG_COLORSPACE_LINEAR_BIT |
321                   EGL_VG_ALPHA_FORMAT_PRE_BIT |
322                   EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
323                   EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
324#ifdef EGL_MESA_screen_surface
325            if (conf->Display->Extensions.MESA_screen_surface)
326               mask |= EGL_SCREEN_BIT_MESA;
327#endif
328            break;
329         case EGL_RENDERABLE_TYPE:
330         case EGL_CONFORMANT:
331            mask = EGL_OPENGL_ES_BIT |
332                   EGL_OPENVG_BIT |
333                   EGL_OPENGL_ES2_BIT |
334                   EGL_OPENGL_ES3_BIT_KHR |
335                   EGL_OPENGL_BIT;
336            break;
337         default:
338            assert(0);
339            mask = 0;
340            break;
341         }
342         if (val & ~mask)
343            valid = EGL_FALSE;
344         break;
345      case ATTRIB_TYPE_PLATFORM:
346         /* unable to check platform-dependent attributes here */
347         break;
348      case ATTRIB_TYPE_PSEUDO:
349         /* pseudo attributes should not be set */
350         if (val != 0)
351            valid = EGL_FALSE;
352         break;
353      default:
354         assert(0);
355         break;
356      }
357
358      if (!valid && for_matching) {
359         /* accept EGL_DONT_CARE as a valid value */
360         if (val == EGL_DONT_CARE)
361            valid = EGL_TRUE;
362         if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
363            valid = EGL_TRUE;
364      }
365      if (!valid) {
366         _eglLog(_EGL_DEBUG,
367               "attribute 0x%04x has an invalid value 0x%x", attr, val);
368         break;
369      }
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 (conf->ColorBufferType) {
379   case EGL_RGB_BUFFER:
380      if (conf->LuminanceSize)
381         valid = EGL_FALSE;
382      if (conf->RedSize + conf->GreenSize +
383            conf->BlueSize + conf->AlphaSize != conf->BufferSize)
384         valid = EGL_FALSE;
385      break;
386   case EGL_LUMINANCE_BUFFER:
387      if (conf->RedSize || conf->GreenSize || conf->BlueSize)
388         valid = EGL_FALSE;
389      if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
390         valid = EGL_FALSE;
391      break;
392   }
393   if (!valid) {
394      _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
395      return EGL_FALSE;
396   }
397
398   if (!conf->SampleBuffers && conf->Samples)
399      valid = EGL_FALSE;
400   if (!valid) {
401      _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
402      return EGL_FALSE;
403   }
404
405   if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
406      if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
407         valid = EGL_FALSE;
408   }
409   if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
410      if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
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 = _eglGetConfigKey(criteria, attr);
443      if (cmp == EGL_DONT_CARE)
444         continue;
445
446      val = _eglGetConfigKey(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#ifndef DEBUG
470         /* only print the common errors when DEBUG is not defined */
471         if (attr != EGL_RENDERABLE_TYPE)
472            break;
473#endif
474         _eglLog(_EGL_DEBUG,
475               "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
476               val, attr, cmp);
477         break;
478      }
479   }
480
481   return matched;
482}
483
484static INLINE EGLBoolean
485_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
486{
487   if (_eglOffsetOfConfig(attr) < 0)
488      return EGL_FALSE;
489
490   switch (attr) {
491   case EGL_Y_INVERTED_NOK:
492      return conf->Display->Extensions.NOK_texture_from_pixmap;
493   default:
494      break;
495   }
496
497   return EGL_TRUE;
498}
499
500/**
501 * Initialize a criteria config from the given attribute list.
502 * Return EGL_FALSE if any of the attribute is invalid.
503 */
504EGLBoolean
505_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
506                          const EGLint *attrib_list)
507{
508   EGLint attr, val, i;
509
510   _eglInitConfig(conf, dpy, EGL_DONT_CARE);
511
512   /* reset to default values */
513   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
514      attr = _eglValidationTable[i].attr;
515      val = _eglValidationTable[i].default_value;
516      _eglSetConfigKey(conf, attr, val);
517   }
518
519   /* parse the list */
520   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
521      attr = attrib_list[i];
522      val = attrib_list[i + 1];
523
524      if (!_eglIsConfigAttribValid(conf, attr))
525	 return EGL_FALSE;
526
527      _eglSetConfigKey(conf, attr, val);
528   }
529
530   if (!_eglValidateConfig(conf, EGL_TRUE))
531      return EGL_FALSE;
532
533   /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
534   if (conf->Level == EGL_DONT_CARE ||
535       conf->MatchNativePixmap == EGL_DONT_CARE)
536      return EGL_FALSE;
537
538   /* ignore other attributes when EGL_CONFIG_ID is given */
539   if (conf->ConfigID != EGL_DONT_CARE) {
540      for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
541         attr = _eglValidationTable[i].attr;
542         if (attr != EGL_CONFIG_ID)
543            _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
544      }
545   }
546   else {
547      if (!(conf->SurfaceType & EGL_WINDOW_BIT))
548         conf->NativeVisualType = EGL_DONT_CARE;
549
550      if (conf->TransparentType == EGL_NONE) {
551         conf->TransparentRedValue = EGL_DONT_CARE;
552         conf->TransparentGreenValue = EGL_DONT_CARE;
553         conf->TransparentBlueValue = EGL_DONT_CARE;
554      }
555   }
556
557   return EGL_TRUE;
558}
559
560
561/**
562 * Decide the ordering of conf1 and conf2, under the given criteria.
563 * When compare_id is true, this implements the algorithm described
564 * in "Sorting of EGLConfigs".  When compare_id is false,
565 * EGL_CONFIG_ID is not compared.
566 *
567 * It returns a negative integer if conf1 is considered to come
568 * before conf2;  a positive integer if conf2 is considered to come
569 * before conf1;  zero if the ordering cannot be decided.
570 *
571 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
572 * ignored here.
573 */
574EGLint
575_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
576                   const _EGLConfig *criteria, EGLBoolean compare_id)
577{
578   const EGLint compare_attribs[] = {
579      EGL_BUFFER_SIZE,
580      EGL_SAMPLE_BUFFERS,
581      EGL_SAMPLES,
582      EGL_DEPTH_SIZE,
583      EGL_STENCIL_SIZE,
584      EGL_ALPHA_MASK_SIZE,
585   };
586   EGLint val1, val2;
587   EGLint i;
588
589   if (conf1 == conf2)
590      return 0;
591
592   /* the enum values have the desired ordering */
593   assert(EGL_NONE < EGL_SLOW_CONFIG);
594   assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
595   val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
596   if (val1)
597      return val1;
598
599   /* the enum values have the desired ordering */
600   assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
601   val1 = conf1->ColorBufferType - conf2->ColorBufferType;
602   if (val1)
603      return val1;
604
605   if (criteria) {
606      val1 = val2 = 0;
607      if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
608         if (criteria->RedSize > 0) {
609            val1 += conf1->RedSize;
610            val2 += conf2->RedSize;
611         }
612         if (criteria->GreenSize > 0) {
613            val1 += conf1->GreenSize;
614            val2 += conf2->GreenSize;
615         }
616         if (criteria->BlueSize > 0) {
617            val1 += conf1->BlueSize;
618            val2 += conf2->BlueSize;
619         }
620      }
621      else {
622         if (criteria->LuminanceSize > 0) {
623            val1 += conf1->LuminanceSize;
624            val2 += conf2->LuminanceSize;
625         }
626      }
627      if (criteria->AlphaSize > 0) {
628         val1 += conf1->AlphaSize;
629         val2 += conf2->AlphaSize;
630      }
631   }
632   else {
633      /* assume the default criteria, which gives no specific ordering */
634      val1 = val2 = 0;
635   }
636
637   /* for color bits, larger one is preferred */
638   if (val1 != val2)
639      return (val2 - val1);
640
641   for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
642      val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
643      val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
644      if (val1 != val2)
645         return (val1 - val2);
646   }
647
648   /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
649
650   return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
651}
652
653
654static INLINE
655void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
656{
657   const _EGLConfig *tmp = *conf1;
658   *conf1 = *conf2;
659   *conf2 = tmp;
660}
661
662
663/**
664 * Quick sort an array of configs.  This differs from the standard
665 * qsort() in that the compare function accepts an additional
666 * argument.
667 */
668static void
669_eglSortConfigs(const _EGLConfig **configs, EGLint count,
670                EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
671                                  void *),
672                void *priv_data)
673{
674   const EGLint pivot = 0;
675   EGLint i, j;
676
677   if (count <= 1)
678      return;
679
680   _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
681   i = 1;
682   j = count - 1;
683   do {
684      while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
685         i++;
686      while (compare(configs[j], configs[pivot], priv_data) > 0)
687         j--;
688      if (i < j) {
689         _eglSwapConfigs(&configs[i], &configs[j]);
690         i++;
691         j--;
692      }
693      else if (i == j) {
694         i++;
695         j--;
696         break;
697      }
698   } while (i <= j);
699   _eglSwapConfigs(&configs[pivot], &configs[j]);
700
701   _eglSortConfigs(configs, j, compare, priv_data);
702   _eglSortConfigs(configs + i, count - i, compare, priv_data);
703}
704
705
706/**
707 * A helper function for implementing eglChooseConfig.  See _eglFilterArray and
708 * _eglSortConfigs for the meanings of match and compare.
709 */
710EGLBoolean
711_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
712                      EGLint config_size, EGLint *num_configs,
713                      EGLBoolean (*match)(const _EGLConfig *, void *),
714                      EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
715                                        void *),
716                      void *priv_data)
717{
718   _EGLConfig **configList;
719   EGLint i, count;
720
721   if (!num_configs)
722      return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
723
724   /* get the number of matched configs */
725   count = _eglFilterArray(array, NULL, 0,
726         (_EGLArrayForEach) match, priv_data);
727   if (!count) {
728      *num_configs = count;
729      return EGL_TRUE;
730   }
731
732   configList = malloc(sizeof(*configList) * count);
733   if (!configList)
734      return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
735
736   /* get the matched configs */
737   _eglFilterArray(array, (void **) configList, count,
738         (_EGLArrayForEach) match, priv_data);
739
740   /* perform sorting of configs */
741   if (configs && count) {
742      _eglSortConfigs((const _EGLConfig **) configList, count,
743                      compare, priv_data);
744      count = MIN2(count, config_size);
745      for (i = 0; i < count; i++)
746         configs[i] = _eglGetConfigHandle(configList[i]);
747   }
748
749   free(configList);
750
751   *num_configs = count;
752
753   return EGL_TRUE;
754}
755
756
757static EGLBoolean
758_eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
759{
760   return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
761}
762
763
764static EGLint
765_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
766                    void *priv_data)
767{
768   return _eglCompareConfigs(conf1, conf2,
769         (const _EGLConfig *) priv_data, EGL_TRUE);
770}
771
772
773/**
774 * Typical fallback routine for eglChooseConfig
775 */
776EGLBoolean
777_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
778                 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
779{
780   _EGLConfig criteria;
781
782   if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
783      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
784
785   return _eglFilterConfigArray(disp->Configs,
786         configs, config_size, num_configs,
787         _eglFallbackMatch, _eglFallbackCompare,
788         (void *) &criteria);
789}
790
791
792/**
793 * Fallback for eglGetConfigAttrib.
794 */
795EGLBoolean
796_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
797                    EGLint attribute, EGLint *value)
798{
799   if (!_eglIsConfigAttribValid(conf, attribute))
800      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
801
802   /* nonqueryable attributes */
803   switch (attribute) {
804   case EGL_MATCH_NATIVE_PIXMAP:
805      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
806      break;
807   default:
808      break;
809   }
810
811   if (!value)
812      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
813
814   *value = _eglGetConfigKey(conf, attribute);
815   return EGL_TRUE;
816}
817
818
819static EGLBoolean
820_eglFlattenConfig(void *elem, void *buffer)
821{
822   _EGLConfig *conf = (_EGLConfig *) elem;
823   EGLConfig *handle = (EGLConfig *) buffer;
824   *handle = _eglGetConfigHandle(conf);
825   return EGL_TRUE;
826}
827
828/**
829 * Fallback for eglGetConfigs.
830 */
831EGLBoolean
832_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
833               EGLint config_size, EGLint *num_config)
834{
835   if (!num_config)
836      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
837
838   *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
839         sizeof(configs[0]), config_size, _eglFlattenConfig);
840
841   return EGL_TRUE;
842}
843