Home | History | Annotate | Download | only in main
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 VMware, Inc.
      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 "c99_compat.h"
     40 #include "util/macros.h"
     41 
     42 #include "eglconfig.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  */
     58 void
     59 _eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
     60 {
     61    memset(conf, 0, sizeof(*conf));
     62 
     63    conf->Display = dpy;
     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  */
     81 EGLConfig
     82 _eglLinkConfig(_EGLConfig *conf)
     83 {
     84    _EGLDisplay *dpy = conf->Display;
     85 
     86    /* sanity check */
     87    assert(dpy);
     88    assert(conf->ConfigID > 0);
     89 
     90    if (!dpy->Configs) {
     91       dpy->Configs = _eglCreateArray("Config", 16);
     92       if (!dpy->Configs)
     93          return (EGLConfig) NULL;
     94    }
     95 
     96    _eglAppendArray(dpy->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 *dpy)
    108 {
    109    _EGLConfig *conf;
    110 
    111    if (!dpy)
    112       return NULL;
    113 
    114    conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
    115    if (conf)
    116       assert(conf->Display == dpy);
    117 
    118    return conf;
    119 }
    120 
    121 
    122 enum 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 
    131 enum 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 */
    141 static 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  */
    272 EGLBoolean
    273 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
    274 {
    275    EGLint i, attr, val;
    276    EGLBoolean valid = EGL_TRUE;
    277 
    278    /* check attributes by their types */
    279    for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    280       EGLint mask;
    281 
    282       attr = _eglValidationTable[i].attr;
    283       val = _eglGetConfigKey(conf, attr);
    284 
    285       switch (_eglValidationTable[i].type) {
    286       case ATTRIB_TYPE_INTEGER:
    287          switch (attr) {
    288          case EGL_CONFIG_ID:
    289             /* config id must be positive */
    290             if (val <= 0)
    291                valid = EGL_FALSE;
    292             break;
    293          case EGL_SAMPLE_BUFFERS:
    294             /* there can be at most 1 sample buffer */
    295             if (val > 1 || val < 0)
    296                valid = EGL_FALSE;
    297             break;
    298          default:
    299             if (val < 0)
    300                valid = EGL_FALSE;
    301             break;
    302          }
    303          break;
    304       case ATTRIB_TYPE_BOOLEAN:
    305          if (val != EGL_TRUE && val != EGL_FALSE)
    306             valid = EGL_FALSE;
    307          break;
    308       case ATTRIB_TYPE_ENUM:
    309          switch (attr) {
    310          case EGL_CONFIG_CAVEAT:
    311             if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
    312                 val != EGL_NON_CONFORMANT_CONFIG)
    313                valid = EGL_FALSE;
    314             break;
    315          case EGL_TRANSPARENT_TYPE:
    316             if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
    317                valid = EGL_FALSE;
    318             break;
    319          case EGL_COLOR_BUFFER_TYPE:
    320             if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
    321                valid = EGL_FALSE;
    322             break;
    323          case EGL_COLOR_COMPONENT_TYPE_EXT:
    324             if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT &&
    325                 val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT)
    326                valid = EGL_FALSE;
    327             break;
    328          default:
    329             assert(0);
    330             break;
    331          }
    332          break;
    333       case ATTRIB_TYPE_BITMASK:
    334          switch (attr) {
    335          case EGL_SURFACE_TYPE:
    336             mask = EGL_PBUFFER_BIT |
    337                    EGL_PIXMAP_BIT |
    338                    EGL_WINDOW_BIT |
    339                    EGL_VG_COLORSPACE_LINEAR_BIT |
    340                    EGL_VG_ALPHA_FORMAT_PRE_BIT |
    341                    EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
    342                    EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    343             break;
    344          case EGL_RENDERABLE_TYPE:
    345          case EGL_CONFORMANT:
    346             mask = EGL_OPENGL_ES_BIT |
    347                    EGL_OPENVG_BIT |
    348                    EGL_OPENGL_ES2_BIT |
    349                    EGL_OPENGL_ES3_BIT_KHR |
    350                    EGL_OPENGL_BIT;
    351             break;
    352          default:
    353             assert(0);
    354             mask = 0;
    355             break;
    356          }
    357          if (val & ~mask)
    358             valid = EGL_FALSE;
    359          break;
    360       case ATTRIB_TYPE_PLATFORM:
    361          /* unable to check platform-dependent attributes here */
    362          break;
    363       case ATTRIB_TYPE_PSEUDO:
    364          /* pseudo attributes should not be set */
    365          if (val != 0)
    366             valid = EGL_FALSE;
    367          break;
    368       }
    369 
    370       if (!valid && for_matching) {
    371          /* accept EGL_DONT_CARE as a valid value */
    372          if (val == EGL_DONT_CARE)
    373             valid = EGL_TRUE;
    374          if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
    375             valid = EGL_TRUE;
    376       }
    377       if (!valid) {
    378          _eglLog(_EGL_DEBUG,
    379                "attribute 0x%04x has an invalid value 0x%x", attr, val);
    380          break;
    381       }
    382    }
    383 
    384    /* any invalid attribute value should have been catched */
    385    if (!valid || for_matching)
    386       return valid;
    387 
    388    /* now check for conflicting attribute values */
    389 
    390    switch (conf->ColorBufferType) {
    391    case EGL_RGB_BUFFER:
    392       if (conf->LuminanceSize)
    393          valid = EGL_FALSE;
    394       if (conf->RedSize + conf->GreenSize +
    395             conf->BlueSize + conf->AlphaSize != conf->BufferSize)
    396          valid = EGL_FALSE;
    397       break;
    398    case EGL_LUMINANCE_BUFFER:
    399       if (conf->RedSize || conf->GreenSize || conf->BlueSize)
    400          valid = EGL_FALSE;
    401       if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
    402          valid = EGL_FALSE;
    403       break;
    404    }
    405    if (!valid) {
    406       _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
    407       return EGL_FALSE;
    408    }
    409 
    410    if (!conf->SampleBuffers && conf->Samples)
    411       valid = EGL_FALSE;
    412    if (!valid) {
    413       _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
    414       return EGL_FALSE;
    415    }
    416 
    417    if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
    418       if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
    419          valid = EGL_FALSE;
    420    }
    421    if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
    422       if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
    423          valid = EGL_FALSE;
    424    }
    425    if (!valid) {
    426       _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
    427       return EGL_FALSE;
    428    }
    429 
    430    return valid;
    431 }
    432 
    433 
    434 /**
    435  * Return true if a config matches the criteria.  This and
    436  * _eglParseConfigAttribList together implement the algorithm
    437  * described in "Selection of EGLConfigs".
    438  *
    439  * Note that attributes that are special (currently, only
    440  * EGL_MATCH_NATIVE_PIXMAP) are ignored.
    441  */
    442 EGLBoolean
    443 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
    444 {
    445    EGLint attr, val, i;
    446    EGLBoolean matched = EGL_TRUE;
    447 
    448    for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    449       EGLint cmp;
    450       if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
    451          continue;
    452 
    453       attr = _eglValidationTable[i].attr;
    454       cmp = _eglGetConfigKey(criteria, attr);
    455       if (cmp == EGL_DONT_CARE)
    456          continue;
    457 
    458       val = _eglGetConfigKey(conf, attr);
    459       switch (_eglValidationTable[i].criterion) {
    460       case ATTRIB_CRITERION_EXACT:
    461          if (val != cmp)
    462             matched = EGL_FALSE;
    463          break;
    464       case ATTRIB_CRITERION_ATLEAST:
    465          if (val < cmp)
    466             matched = EGL_FALSE;
    467          break;
    468       case ATTRIB_CRITERION_MASK:
    469          if ((val & cmp) != cmp)
    470             matched = EGL_FALSE;
    471          break;
    472       case ATTRIB_CRITERION_SPECIAL:
    473          /* ignored here */
    474          break;
    475       case ATTRIB_CRITERION_IGNORE:
    476          unreachable("already handled above");
    477          break;
    478       }
    479 
    480       if (!matched) {
    481 #ifndef DEBUG
    482          /* only print the common errors when DEBUG is not defined */
    483          if (attr != EGL_RENDERABLE_TYPE)
    484             break;
    485 #endif
    486          _eglLog(_EGL_DEBUG,
    487                "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
    488                val, attr, cmp);
    489          break;
    490       }
    491    }
    492 
    493    return matched;
    494 }
    495 
    496 static inline EGLBoolean
    497 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
    498 {
    499    if (_eglOffsetOfConfig(attr) < 0)
    500       return EGL_FALSE;
    501 
    502    switch (attr) {
    503    case EGL_Y_INVERTED_NOK:
    504       return conf->Display->Extensions.NOK_texture_from_pixmap;
    505    case EGL_FRAMEBUFFER_TARGET_ANDROID:
    506       return conf->Display->Extensions.ANDROID_framebuffer_target;
    507    case EGL_RECORDABLE_ANDROID:
    508       return conf->Display->Extensions.ANDROID_recordable;
    509    default:
    510       break;
    511    }
    512 
    513    return EGL_TRUE;
    514 }
    515 
    516 /**
    517  * Initialize a criteria config from the given attribute list.
    518  * Return EGL_FALSE if any of the attribute is invalid.
    519  */
    520 EGLBoolean
    521 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
    522                           const EGLint *attrib_list)
    523 {
    524    EGLint attr, val, i;
    525 
    526    _eglInitConfig(conf, dpy, EGL_DONT_CARE);
    527 
    528    /* reset to default values */
    529    for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    530       attr = _eglValidationTable[i].attr;
    531       val = _eglValidationTable[i].default_value;
    532       _eglSetConfigKey(conf, attr, val);
    533    }
    534 
    535    /* parse the list */
    536    for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
    537       attr = attrib_list[i];
    538       val = attrib_list[i + 1];
    539 
    540       if (!_eglIsConfigAttribValid(conf, attr))
    541 	 return EGL_FALSE;
    542 
    543       _eglSetConfigKey(conf, attr, val);
    544    }
    545 
    546    if (!_eglValidateConfig(conf, EGL_TRUE))
    547       return EGL_FALSE;
    548 
    549    /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
    550    if (conf->Level == EGL_DONT_CARE ||
    551        conf->MatchNativePixmap == EGL_DONT_CARE)
    552       return EGL_FALSE;
    553 
    554    /* ignore other attributes when EGL_CONFIG_ID is given */
    555    if (conf->ConfigID != EGL_DONT_CARE) {
    556       for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
    557          attr = _eglValidationTable[i].attr;
    558          if (attr != EGL_CONFIG_ID)
    559             _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
    560       }
    561    }
    562    else {
    563       if (!(conf->SurfaceType & EGL_WINDOW_BIT))
    564          conf->NativeVisualType = EGL_DONT_CARE;
    565 
    566       if (conf->TransparentType == EGL_NONE) {
    567          conf->TransparentRedValue = EGL_DONT_CARE;
    568          conf->TransparentGreenValue = EGL_DONT_CARE;
    569          conf->TransparentBlueValue = EGL_DONT_CARE;
    570       }
    571    }
    572 
    573    return EGL_TRUE;
    574 }
    575 
    576 
    577 /**
    578  * Decide the ordering of conf1 and conf2, under the given criteria.
    579  * When compare_id is true, this implements the algorithm described
    580  * in "Sorting of EGLConfigs".  When compare_id is false,
    581  * EGL_CONFIG_ID is not compared.
    582  *
    583  * It returns a negative integer if conf1 is considered to come
    584  * before conf2;  a positive integer if conf2 is considered to come
    585  * before conf1;  zero if the ordering cannot be decided.
    586  *
    587  * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
    588  * ignored here.
    589  */
    590 EGLint
    591 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
    592                    const _EGLConfig *criteria, EGLBoolean compare_id)
    593 {
    594    const EGLint compare_attribs[] = {
    595       EGL_BUFFER_SIZE,
    596       EGL_SAMPLE_BUFFERS,
    597       EGL_SAMPLES,
    598       EGL_DEPTH_SIZE,
    599       EGL_STENCIL_SIZE,
    600       EGL_ALPHA_MASK_SIZE,
    601    };
    602    EGLint val1, val2;
    603    EGLint i;
    604 
    605    if (conf1 == conf2)
    606       return 0;
    607 
    608    /* the enum values have the desired ordering */
    609    STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG);
    610    STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    611    val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
    612    if (val1)
    613       return val1;
    614 
    615    /* the enum values have the desired ordering */
    616    STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    617    val1 = conf1->ColorBufferType - conf2->ColorBufferType;
    618    if (val1)
    619       return val1;
    620 
    621    if (criteria) {
    622       val1 = val2 = 0;
    623       if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
    624          if (criteria->RedSize > 0) {
    625             val1 += conf1->RedSize;
    626             val2 += conf2->RedSize;
    627          }
    628          if (criteria->GreenSize > 0) {
    629             val1 += conf1->GreenSize;
    630             val2 += conf2->GreenSize;
    631          }
    632          if (criteria->BlueSize > 0) {
    633             val1 += conf1->BlueSize;
    634             val2 += conf2->BlueSize;
    635          }
    636       }
    637       else {
    638          if (criteria->LuminanceSize > 0) {
    639             val1 += conf1->LuminanceSize;
    640             val2 += conf2->LuminanceSize;
    641          }
    642       }
    643       if (criteria->AlphaSize > 0) {
    644          val1 += conf1->AlphaSize;
    645          val2 += conf2->AlphaSize;
    646       }
    647    }
    648    else {
    649       /* assume the default criteria, which gives no specific ordering */
    650       val1 = val2 = 0;
    651    }
    652 
    653    /* for color bits, larger one is preferred */
    654    if (val1 != val2)
    655       return (val2 - val1);
    656 
    657    for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
    658       val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
    659       val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
    660       if (val1 != val2)
    661          return (val1 - val2);
    662    }
    663 
    664    /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
    665 
    666    return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
    667 }
    668 
    669 
    670 static inline
    671 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
    672 {
    673    const _EGLConfig *tmp = *conf1;
    674    *conf1 = *conf2;
    675    *conf2 = tmp;
    676 }
    677 
    678 
    679 /**
    680  * Quick sort an array of configs.  This differs from the standard
    681  * qsort() in that the compare function accepts an additional
    682  * argument.
    683  */
    684 static void
    685 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
    686                 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
    687                                   void *),
    688                 void *priv_data)
    689 {
    690    const EGLint pivot = 0;
    691    EGLint i, j;
    692 
    693    if (count <= 1)
    694       return;
    695 
    696    _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
    697    i = 1;
    698    j = count - 1;
    699    do {
    700       while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
    701          i++;
    702       while (compare(configs[j], configs[pivot], priv_data) > 0)
    703          j--;
    704       if (i < j) {
    705          _eglSwapConfigs(&configs[i], &configs[j]);
    706          i++;
    707          j--;
    708       }
    709       else if (i == j) {
    710          i++;
    711          j--;
    712          break;
    713       }
    714    } while (i <= j);
    715    _eglSwapConfigs(&configs[pivot], &configs[j]);
    716 
    717    _eglSortConfigs(configs, j, compare, priv_data);
    718    _eglSortConfigs(configs + i, count - i, compare, priv_data);
    719 }
    720 
    721 
    722 /**
    723  * A helper function for implementing eglChooseConfig.  See _eglFilterArray and
    724  * _eglSortConfigs for the meanings of match and compare.
    725  */
    726 EGLBoolean
    727 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
    728                       EGLint config_size, EGLint *num_configs,
    729                       EGLBoolean (*match)(const _EGLConfig *, void *),
    730                       EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
    731                                         void *),
    732                       void *priv_data)
    733 {
    734    _EGLConfig **configList;
    735    EGLint i, count;
    736 
    737    if (!num_configs)
    738       return _eglError(EGL_BAD_PARAMETER, "eglChooseConfig");
    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 
    773 static EGLBoolean
    774 _eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
    775 {
    776    return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
    777 }
    778 
    779 
    780 static 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  */
    792 EGLBoolean
    793 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
    794                  EGLConfig *configs, EGLint config_size, EGLint *num_configs)
    795 {
    796    _EGLConfig criteria;
    797 
    798    if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
    799       return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
    800 
    801    return _eglFilterConfigArray(disp->Configs,
    802          configs, config_size, num_configs,
    803          _eglFallbackMatch, _eglFallbackCompare,
    804          (void *) &criteria);
    805 }
    806 
    807 
    808 /**
    809  * Fallback for eglGetConfigAttrib.
    810  */
    811 EGLBoolean
    812 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
    813                     EGLint attribute, EGLint *value)
    814 {
    815    if (!_eglIsConfigAttribValid(conf, attribute))
    816       return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
    817 
    818    /* nonqueryable attributes */
    819    switch (attribute) {
    820    case EGL_MATCH_NATIVE_PIXMAP:
    821       return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
    822       break;
    823    default:
    824       break;
    825    }
    826 
    827    if (!value)
    828       return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
    829 
    830    *value = _eglGetConfigKey(conf, attribute);
    831    return EGL_TRUE;
    832 }
    833 
    834 
    835 static EGLBoolean
    836 _eglFlattenConfig(void *elem, void *buffer)
    837 {
    838    _EGLConfig *conf = (_EGLConfig *) elem;
    839    EGLConfig *handle = (EGLConfig *) buffer;
    840    *handle = _eglGetConfigHandle(conf);
    841    return EGL_TRUE;
    842 }
    843 
    844 /**
    845  * Fallback for eglGetConfigs.
    846  */
    847 EGLBoolean
    848 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
    849                EGLint config_size, EGLint *num_config)
    850 {
    851    if (!num_config)
    852       return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
    853 
    854    *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
    855          sizeof(configs[0]), config_size, _eglFlattenConfig);
    856 
    857    return EGL_TRUE;
    858 }
    859