Home | History | Annotate | Download | only in main
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * Copyright 2009-2010 Chia-I Wu <olvaffe (at) 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  */
     56 void
     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  */
     78 PUBLIC 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 
    118 enum {
    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 */
    136 static 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  */
    258 EGLBoolean
    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_BIT;
    335             break;
    336          default:
    337             assert(0);
    338             mask = 0;
    339             break;
    340          }
    341          if (val & ~mask)
    342             valid = EGL_FALSE;
    343          break;
    344       case ATTRIB_TYPE_PLATFORM:
    345          /* unable to check platform-dependent attributes here */
    346          break;
    347       case ATTRIB_TYPE_PSEUDO:
    348          /* pseudo attributes should not be set */
    349          if (val != 0)
    350             valid = EGL_FALSE;
    351          break;
    352       default:
    353          assert(0);
    354          break;
    355       }
    356 
    357       if (!valid && for_matching) {
    358          /* accept EGL_DONT_CARE as a valid value */
    359          if (val == EGL_DONT_CARE)
    360             valid = EGL_TRUE;
    361          if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
    362             valid = EGL_TRUE;
    363       }
    364       if (!valid) {
    365          _eglLog(_EGL_DEBUG,
    366                "attribute 0x%04x has an invalid value 0x%x", attr, val);
    367          break;
    368       }
    369    }
    370 
    371    /* any invalid attribute value should have been catched */
    372    if (!valid || for_matching)
    373       return valid;
    374 
    375    /* now check for conflicting attribute values */
    376 
    377    switch (conf->ColorBufferType) {
    378    case EGL_RGB_BUFFER:
    379       if (conf->LuminanceSize)
    380          valid = EGL_FALSE;
    381       if (conf->RedSize + conf->GreenSize +
    382             conf->BlueSize + conf->AlphaSize != conf->BufferSize)
    383          valid = EGL_FALSE;
    384       break;
    385    case EGL_LUMINANCE_BUFFER:
    386       if (conf->RedSize || conf->GreenSize || conf->BlueSize)
    387          valid = EGL_FALSE;
    388       if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
    389          valid = EGL_FALSE;
    390       break;
    391    }
    392    if (!valid) {
    393       _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
    394       return EGL_FALSE;
    395    }
    396 
    397    if (!conf->SampleBuffers && conf->Samples)
    398       valid = EGL_FALSE;
    399    if (!valid) {
    400       _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
    401       return EGL_FALSE;
    402    }
    403 
    404    if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
    405       if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
    406          valid = EGL_FALSE;
    407    }
    408    if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
    409       if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
    410          valid = EGL_FALSE;
    411    }
    412    if (!valid) {
    413       _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
    414       return EGL_FALSE;
    415    }
    416 
    417    return valid;
    418 }
    419 
    420 
    421 /**
    422  * Return true if a config matches the criteria.  This and
    423  * _eglParseConfigAttribList together implement the algorithm
    424  * described in "Selection of EGLConfigs".
    425  *
    426  * Note that attributes that are special (currently, only
    427  * EGL_MATCH_NATIVE_PIXMAP) are ignored.
    428  */
    429 EGLBoolean
    430 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
    431 {
    432    EGLint attr, val, i;
    433    EGLBoolean matched = EGL_TRUE;
    434 
    435    for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    436       EGLint cmp;
    437       if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
    438          continue;
    439 
    440       attr = _eglValidationTable[i].attr;
    441       cmp = _eglGetConfigKey(criteria, attr);
    442       if (cmp == EGL_DONT_CARE)
    443          continue;
    444 
    445       val = _eglGetConfigKey(conf, attr);
    446       switch (_eglValidationTable[i].criterion) {
    447       case ATTRIB_CRITERION_EXACT:
    448          if (val != cmp)
    449             matched = EGL_FALSE;
    450          break;
    451       case ATTRIB_CRITERION_ATLEAST:
    452          if (val < cmp)
    453             matched = EGL_FALSE;
    454          break;
    455       case ATTRIB_CRITERION_MASK:
    456          if ((val & cmp) != cmp)
    457             matched = EGL_FALSE;
    458          break;
    459       case ATTRIB_CRITERION_SPECIAL:
    460          /* ignored here */
    461          break;
    462       default:
    463          assert(0);
    464          break;
    465       }
    466 
    467       if (!matched) {
    468 #ifndef DEBUG
    469          /* only print the common errors when DEBUG is not defined */
    470          if (attr != EGL_RENDERABLE_TYPE)
    471             break;
    472 #endif
    473          _eglLog(_EGL_DEBUG,
    474                "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
    475                val, attr, cmp);
    476          break;
    477       }
    478    }
    479 
    480    return matched;
    481 }
    482 
    483 static INLINE EGLBoolean
    484 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
    485 {
    486    if (_eglOffsetOfConfig(attr) < 0)
    487       return EGL_FALSE;
    488 
    489    switch (attr) {
    490    case EGL_Y_INVERTED_NOK:
    491       return conf->Display->Extensions.NOK_texture_from_pixmap;
    492    default:
    493       break;
    494    }
    495 
    496    return EGL_TRUE;
    497 }
    498 
    499 /**
    500  * Initialize a criteria config from the given attribute list.
    501  * Return EGL_FALSE if any of the attribute is invalid.
    502  */
    503 EGLBoolean
    504 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
    505                           const EGLint *attrib_list)
    506 {
    507    EGLint attr, val, i;
    508 
    509    _eglInitConfig(conf, dpy, EGL_DONT_CARE);
    510 
    511    /* reset to default values */
    512    for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    513       attr = _eglValidationTable[i].attr;
    514       val = _eglValidationTable[i].default_value;
    515       _eglSetConfigKey(conf, attr, val);
    516    }
    517 
    518    /* parse the list */
    519    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
    520       attr = attrib_list[i];
    521       val = attrib_list[i + 1];
    522 
    523       if (!_eglIsConfigAttribValid(conf, attr))
    524 	 return EGL_FALSE;
    525 
    526       _eglSetConfigKey(conf, attr, val);
    527    }
    528 
    529    if (!_eglValidateConfig(conf, EGL_TRUE))
    530       return EGL_FALSE;
    531 
    532    /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
    533    if (conf->Level == EGL_DONT_CARE ||
    534        conf->MatchNativePixmap == EGL_DONT_CARE)
    535       return EGL_FALSE;
    536 
    537    /* ignore other attributes when EGL_CONFIG_ID is given */
    538    if (conf->ConfigID != EGL_DONT_CARE) {
    539       for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    540          attr = _eglValidationTable[i].attr;
    541          if (attr != EGL_CONFIG_ID)
    542             _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
    543       }
    544    }
    545    else {
    546       if (!(conf->SurfaceType & EGL_WINDOW_BIT))
    547          conf->NativeVisualType = EGL_DONT_CARE;
    548 
    549       if (conf->TransparentType == EGL_NONE) {
    550          conf->TransparentRedValue = EGL_DONT_CARE;
    551          conf->TransparentGreenValue = EGL_DONT_CARE;
    552          conf->TransparentBlueValue = EGL_DONT_CARE;
    553       }
    554    }
    555 
    556    return EGL_TRUE;
    557 }
    558 
    559 
    560 /**
    561  * Decide the ordering of conf1 and conf2, under the given criteria.
    562  * When compare_id is true, this implements the algorithm described
    563  * in "Sorting of EGLConfigs".  When compare_id is false,
    564  * EGL_CONFIG_ID is not compared.
    565  *
    566  * It returns a negative integer if conf1 is considered to come
    567  * before conf2;  a positive integer if conf2 is considered to come
    568  * before conf1;  zero if the ordering cannot be decided.
    569  *
    570  * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
    571  * ignored here.
    572  */
    573 EGLint
    574 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
    575                    const _EGLConfig *criteria, EGLBoolean compare_id)
    576 {
    577    const EGLint compare_attribs[] = {
    578       EGL_BUFFER_SIZE,
    579       EGL_SAMPLE_BUFFERS,
    580       EGL_SAMPLES,
    581       EGL_DEPTH_SIZE,
    582       EGL_STENCIL_SIZE,
    583       EGL_ALPHA_MASK_SIZE,
    584    };
    585    EGLint val1, val2;
    586    EGLint i;
    587 
    588    if (conf1 == conf2)
    589       return 0;
    590 
    591    /* the enum values have the desired ordering */
    592    assert(EGL_NONE < EGL_SLOW_CONFIG);
    593    assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    594    val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
    595    if (val1)
    596       return val1;
    597 
    598    /* the enum values have the desired ordering */
    599    assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    600    val1 = conf1->ColorBufferType - conf2->ColorBufferType;
    601    if (val1)
    602       return val1;
    603 
    604    if (criteria) {
    605       val1 = val2 = 0;
    606       if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
    607          if (criteria->RedSize > 0) {
    608             val1 += conf1->RedSize;
    609             val2 += conf2->RedSize;
    610          }
    611          if (criteria->GreenSize > 0) {
    612             val1 += conf1->GreenSize;
    613             val2 += conf2->GreenSize;
    614          }
    615          if (criteria->BlueSize > 0) {
    616             val1 += conf1->BlueSize;
    617             val2 += conf2->BlueSize;
    618          }
    619       }
    620       else {
    621          if (criteria->LuminanceSize > 0) {
    622             val1 += conf1->LuminanceSize;
    623             val2 += conf2->LuminanceSize;
    624          }
    625       }
    626       if (criteria->AlphaSize > 0) {
    627          val1 += conf1->AlphaSize;
    628          val2 += conf2->AlphaSize;
    629       }
    630    }
    631    else {
    632       /* assume the default criteria, which gives no specific ordering */
    633       val1 = val2 = 0;
    634    }
    635 
    636    /* for color bits, larger one is preferred */
    637    if (val1 != val2)
    638       return (val2 - val1);
    639 
    640    for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
    641       val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
    642       val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
    643       if (val1 != val2)
    644          return (val1 - val2);
    645    }
    646 
    647    /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
    648 
    649    return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
    650 }
    651 
    652 
    653 static INLINE
    654 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
    655 {
    656    const _EGLConfig *tmp = *conf1;
    657    *conf1 = *conf2;
    658    *conf2 = tmp;
    659 }
    660 
    661 
    662 /**
    663  * Quick sort an array of configs.  This differs from the standard
    664  * qsort() in that the compare function accepts an additional
    665  * argument.
    666  */
    667 static void
    668 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
    669                 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
    670                                   void *),
    671                 void *priv_data)
    672 {
    673    const EGLint pivot = 0;
    674    EGLint i, j;
    675 
    676    if (count <= 1)
    677       return;
    678 
    679    _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
    680    i = 1;
    681    j = count - 1;
    682    do {
    683       while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
    684          i++;
    685       while (compare(configs[j], configs[pivot], priv_data) > 0)
    686          j--;
    687       if (i < j) {
    688          _eglSwapConfigs(&configs[i], &configs[j]);
    689          i++;
    690          j--;
    691       }
    692       else if (i == j) {
    693          i++;
    694          j--;
    695          break;
    696       }
    697    } while (i <= j);
    698    _eglSwapConfigs(&configs[pivot], &configs[j]);
    699 
    700    _eglSortConfigs(configs, j, compare, priv_data);
    701    _eglSortConfigs(configs + i, count - i, compare, priv_data);
    702 }
    703 
    704 
    705 /**
    706  * A helper function for implementing eglChooseConfig.  See _eglFilterArray and
    707  * _eglSortConfigs for the meanings of match and compare.
    708  */
    709 EGLBoolean
    710 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
    711                       EGLint config_size, EGLint *num_configs,
    712                       EGLBoolean (*match)(const _EGLConfig *, void *),
    713                       EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
    714                                         void *),
    715                       void *priv_data)
    716 {
    717    _EGLConfig **configList;
    718    EGLint i, count;
    719 
    720    if (!num_configs)
    721       return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
    722 
    723    /* get the number of matched configs */
    724    count = _eglFilterArray(array, NULL, 0,
    725          (_EGLArrayForEach) match, priv_data);
    726    if (!count) {
    727       *num_configs = count;
    728       return EGL_TRUE;
    729    }
    730 
    731    configList = malloc(sizeof(*configList) * count);
    732    if (!configList)
    733       return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
    734 
    735    /* get the matched configs */
    736    _eglFilterArray(array, (void **) configList, count,
    737          (_EGLArrayForEach) match, priv_data);
    738 
    739    /* perform sorting of configs */
    740    if (configs && count) {
    741       _eglSortConfigs((const _EGLConfig **) configList, count,
    742                       compare, priv_data);
    743       count = MIN2(count, config_size);
    744       for (i = 0; i < count; i++)
    745          configs[i] = _eglGetConfigHandle(configList[i]);
    746    }
    747 
    748    free(configList);
    749 
    750    *num_configs = count;
    751 
    752    return EGL_TRUE;
    753 }
    754 
    755 
    756 static EGLBoolean
    757 _eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
    758 {
    759    return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
    760 }
    761 
    762 
    763 static EGLint
    764 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
    765                     void *priv_data)
    766 {
    767    return _eglCompareConfigs(conf1, conf2,
    768          (const _EGLConfig *) priv_data, EGL_TRUE);
    769 }
    770 
    771 
    772 /**
    773  * Typical fallback routine for eglChooseConfig
    774  */
    775 EGLBoolean
    776 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
    777                  EGLConfig *configs, EGLint config_size, EGLint *num_configs)
    778 {
    779    _EGLConfig criteria;
    780 
    781    if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
    782       return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
    783 
    784    return _eglFilterConfigArray(disp->Configs,
    785          configs, config_size, num_configs,
    786          _eglFallbackMatch, _eglFallbackCompare,
    787          (void *) &criteria);
    788 }
    789 
    790 
    791 /**
    792  * Fallback for eglGetConfigAttrib.
    793  */
    794 EGLBoolean
    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 
    801    /* nonqueryable attributes */
    802    switch (attribute) {
    803    case EGL_MATCH_NATIVE_PIXMAP:
    804       return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
    805       break;
    806    default:
    807       break;
    808    }
    809 
    810    if (!value)
    811       return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
    812 
    813    *value = _eglGetConfigKey(conf, attribute);
    814    return EGL_TRUE;
    815 }
    816 
    817 
    818 static EGLBoolean
    819 _eglFlattenConfig(void *elem, void *buffer)
    820 {
    821    _EGLConfig *conf = (_EGLConfig *) elem;
    822    EGLConfig *handle = (EGLConfig *) buffer;
    823    *handle = _eglGetConfigHandle(conf);
    824    return EGL_TRUE;
    825 }
    826 
    827 /**
    828  * Fallback for eglGetConfigs.
    829  */
    830 EGLBoolean
    831 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
    832                EGLint config_size, EGLint *num_config)
    833 {
    834    if (!num_config)
    835       return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
    836 
    837    *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
    838          sizeof(configs[0]), config_size, _eglFlattenConfig);
    839 
    840    return EGL_TRUE;
    841 }
    842