Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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