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