X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fmain%2Feglconfig.c;h=4d313a9bb5b44e29cdd6f3e513dbad1e250b9468;hb=cd6a31cd4a9ea6deef4778c2eaef2d47240c3a6e;hp=d47b99eed4b4b6a3947a8354c7536370564f1c06;hpb=82c2f7756af19f0a19aeda7ea1f627262e4561c0;p=mesa.git diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index d47b99eed4b..4d313a9bb5b 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -4,313 +4,669 @@ #include -#include #include #include #include "eglconfig.h" #include "egldisplay.h" -#include "egldriver.h" -#include "eglglobals.h" +#include "eglcurrent.h" #include "egllog.h" #define MIN2(A, B) (((A) < (B)) ? (A) : (B)) -void -_eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val) -{ - assert(attr >= FIRST_ATTRIB); - assert(attr < FIRST_ATTRIB + MAX_ATTRIBS); - config->Attrib[attr - FIRST_ATTRIB] = val; -} - - /** * Init the given _EGLconfig to default values. * \param id the configuration's ID. + * + * Note that id must be positive for the config to be valid. + * It is also recommended that when there are N configs, their + * IDs are from 1 to N respectively. */ void -_eglInitConfig(_EGLConfig *config, EGLint id) +_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id) { - memset(config, 0, sizeof(*config)); - config->Handle = (EGLConfig) _eglUIntToPointer((unsigned int) id); - _eglSetConfigAttrib(config, EGL_CONFIG_ID, id); - _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_CONFIG_CAVEAT, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_NATIVE_RENDERABLE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_TYPE, EGL_NONE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE); - _eglSetConfigAttrib(config, EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE); -#ifdef EGL_VERSION_1_2 - _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); - _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); -#endif /* EGL_VERSION_1_2 */ + memset(conf, 0, sizeof(*conf)); + + conf->Display = dpy; + + /* some attributes take non-zero default values */ + conf->ConfigID = id; + conf->ConfigCaveat = EGL_NONE; + conf->TransparentType = EGL_NONE; + conf->NativeVisualType = EGL_NONE; + conf->ColorBufferType = EGL_RGB_BUFFER; } /** - * Return the public handle for an internal _EGLConfig. - * This is the inverse of _eglLookupConfig(). + * Link a config to a display and return the handle of the link. + * The handle can be passed to client directly. + * + * Note that we just save the ptr to the config (we don't copy the config). */ EGLConfig -_eglGetConfigHandle(_EGLConfig *config) +_eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf) { - return config ? config->Handle : 0; + /* sanity check */ + assert(conf->ConfigID > 0); + + if (!dpy->Configs) { + dpy->Configs = _eglCreateArray("Config", 16); + if (!dpy->Configs) + return (EGLConfig) NULL; + } + + conf->Display = dpy; + _eglAppendArray(dpy->Configs, (void *) conf); + + return (EGLConfig) conf; } -/** - * Given an EGLConfig handle, return the corresponding _EGLConfig object. - * This is the inverse of _eglGetConfigHandle(). - */ -_EGLConfig * -_eglLookupConfig(EGLConfig config, _EGLDisplay *disp) +EGLBoolean +_eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy) { - EGLint i; - for (i = 0; i < disp->NumConfigs; i++) { - if (disp->Configs[i]->Handle == config) { - return disp->Configs[i]; - } - } - return NULL; + _EGLConfig *conf; + + conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config); + if (conf) + assert(conf->Display == dpy); + + return (conf != NULL); } -/** - * Add the given _EGLConfig to the given display. - * Note that we just save the ptr to the config (we don't copy the config). - */ -_EGLConfig * -_eglAddConfig(_EGLDisplay *display, _EGLConfig *config) +enum { + /* types */ + ATTRIB_TYPE_INTEGER, + ATTRIB_TYPE_BOOLEAN, + ATTRIB_TYPE_BITMASK, + ATTRIB_TYPE_ENUM, + ATTRIB_TYPE_PSEUDO, /* non-queryable */ + ATTRIB_TYPE_PLATFORM, /* platform-dependent */ + /* criteria */ + ATTRIB_CRITERION_EXACT, + ATTRIB_CRITERION_ATLEAST, + ATTRIB_CRITERION_MASK, + ATTRIB_CRITERION_SPECIAL, + ATTRIB_CRITERION_IGNORE +}; + + +/* EGL spec Table 3.1 and 3.4 */ +static const struct { + EGLint attr; + EGLint type; + EGLint criterion; + EGLint default_value; +} _eglValidationTable[] = { - _EGLConfig **newConfigs; - EGLint n; - - /* do some sanity checks on the config's attribs */ - assert(GET_CONFIG_ATTRIB(config, EGL_CONFIG_ID) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE) != 0x0); - assert(GET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE) != 0x0); - assert(GET_CONFIG_ATTRIB(config, EGL_RED_SIZE) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE) > 0); - assert(GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE) > 0); - - n = display->NumConfigs; - - /* realloc array of ptrs */ - newConfigs = (_EGLConfig **) realloc(display->Configs, - (n + 1) * sizeof(_EGLConfig *)); - if (newConfigs) { - display->Configs = newConfigs; - display->Configs[n] = config; - display->NumConfigs++; - return config; - } - else { - return NULL; - } -} + /* core */ + { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_RGB_BUFFER }, + { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + 0 }, + { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_EXACT, + 0 }, + { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_IGNORE, + 0 }, + { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + EGL_OPENGL_ES_BIT }, + { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, + ATTRIB_CRITERION_MASK, + EGL_WINDOW_BIT }, + { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_NONE }, + { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, + ATTRIB_CRITERION_SPECIAL, + EGL_NONE }, + /* extensions */ + { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE } +}; /** - * Parse the attrib_list to fill in the fields of the given _eglConfig - * Return EGL_FALSE if any errors, EGL_TRUE otherwise. + * Return true if a config is valid. When for_matching is true, + * EGL_DONT_CARE is accepted as a valid attribute value, and checks + * for conflicting attribute values are skipped. + * + * Note that some attributes are platform-dependent and are not + * checked. */ EGLBoolean -_eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list) +_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) { - EGLint i; - - /* set all config attribs to EGL_DONT_CARE */ - for (i = 0; i < MAX_ATTRIBS; i++) { - config->Attrib[i] = EGL_DONT_CARE; - } - - /* by default choose windows unless otherwise specified */ - config->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] = EGL_WINDOW_BIT; - - for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) { - const EGLint attr = attrib_list[i]; - if (attr >= EGL_BUFFER_SIZE && - attr <= EGL_MAX_SWAP_INTERVAL) { - EGLint k = attr - FIRST_ATTRIB; - assert(k >= 0); - assert(k < MAX_ATTRIBS); - config->Attrib[k] = attrib_list[++i]; - } -#ifdef EGL_VERSION_1_2 - else if (attr == EGL_COLOR_BUFFER_TYPE) { - EGLint bufType = attrib_list[++i]; - if (bufType != EGL_RGB_BUFFER && bufType != EGL_LUMINANCE_BUFFER) { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + EGLint i, attr, val; + EGLBoolean valid = EGL_TRUE; + + /* check attributes by their types */ + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + EGLint mask; + + attr = _eglValidationTable[i].attr; + val = _eglGetConfigKey(conf, attr); + + switch (_eglValidationTable[i].type) { + case ATTRIB_TYPE_INTEGER: + switch (attr) { + case EGL_CONFIG_ID: + /* config id must be positive */ + if (val <= 0) + valid = EGL_FALSE; + break; + case EGL_SAMPLE_BUFFERS: + /* there can be at most 1 sample buffer */ + if (val > 1 || val < 0) + valid = EGL_FALSE; + break; + default: + if (val < 0) + valid = EGL_FALSE; + break; } - _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, bufType); - } - else if (attr == EGL_RENDERABLE_TYPE) { - EGLint renType = attrib_list[++i]; - if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENVG_BIT)) { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + break; + case ATTRIB_TYPE_BOOLEAN: + if (val != EGL_TRUE && val != EGL_FALSE) + valid = EGL_FALSE; + break; + case ATTRIB_TYPE_ENUM: + switch (attr) { + case EGL_CONFIG_CAVEAT: + if (val != EGL_NONE && val != EGL_SLOW_CONFIG && + val != EGL_NON_CONFORMANT_CONFIG) + valid = EGL_FALSE; + break; + case EGL_TRANSPARENT_TYPE: + if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) + valid = EGL_FALSE; + break; + case EGL_COLOR_BUFFER_TYPE: + if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) + valid = EGL_FALSE; + break; + default: + assert(0); + break; + } + break; + case ATTRIB_TYPE_BITMASK: + switch (attr) { + case EGL_SURFACE_TYPE: + mask = EGL_PBUFFER_BIT | + EGL_PIXMAP_BIT | + EGL_WINDOW_BIT | + EGL_VG_COLORSPACE_LINEAR_BIT | + EGL_VG_ALPHA_FORMAT_PRE_BIT | + EGL_MULTISAMPLE_RESOLVE_BOX_BIT | + EGL_SWAP_BEHAVIOR_PRESERVED_BIT; +#ifdef EGL_MESA_screen_surface + if (conf->Display->Extensions.MESA_screen_surface) + mask |= EGL_SCREEN_BIT_MESA; +#endif + break; + case EGL_RENDERABLE_TYPE: + case EGL_CONFORMANT: + mask = EGL_OPENGL_ES_BIT | + EGL_OPENVG_BIT | + EGL_OPENGL_ES2_BIT | + EGL_OPENGL_BIT; + break; + default: + assert(0); + break; } - _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, renType); + if (val & ~mask) + valid = EGL_FALSE; + break; + case ATTRIB_TYPE_PLATFORM: + /* unable to check platform-dependent attributes here */ + break; + case ATTRIB_TYPE_PSEUDO: + /* pseudo attributes should not be set */ + if (val != 0) + valid = EGL_FALSE; + break; + default: + assert(0); + break; } - else if (attr == EGL_ALPHA_MASK_SIZE || - attr == EGL_LUMINANCE_SIZE) { - EGLint value = attrib_list[++i]; - _eglSetConfigAttrib(config, attr, value); + + if (!valid && for_matching) { + /* accept EGL_DONT_CARE as a valid value */ + if (val == EGL_DONT_CARE) + valid = EGL_TRUE; + if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) + valid = EGL_TRUE; } -#endif /* EGL_VERSION_1_2 */ - else { - _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); - return EGL_FALSE; + if (!valid) { + _eglLog(_EGL_DEBUG, + "attribute 0x%04x has an invalid value 0x%x", attr, val); + break; } } - return EGL_TRUE; -} + /* any invalid attribute value should have been catched */ + if (!valid || for_matching) + return valid; + + /* now check for conflicting attribute values */ + + switch (conf->ColorBufferType) { + case EGL_RGB_BUFFER: + if (conf->LuminanceSize) + valid = EGL_FALSE; + if (conf->RedSize + conf->GreenSize + + conf->BlueSize + conf->AlphaSize != conf->BufferSize) + valid = EGL_FALSE; + break; + case EGL_LUMINANCE_BUFFER: + if (conf->RedSize || conf->GreenSize || conf->BlueSize) + valid = EGL_FALSE; + if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) + valid = EGL_FALSE; + break; + } + if (!valid) { + _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); + return EGL_FALSE; + } + + if (!conf->SampleBuffers && conf->Samples) + valid = EGL_FALSE; + if (!valid) { + _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); + return EGL_FALSE; + } + + if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { + if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) + valid = EGL_FALSE; + } + if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { + if (conf->BindToTextureRGB || conf->BindToTextureRGBA) + valid = EGL_FALSE; + } + if (!valid) { + _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); + return EGL_FALSE; + } -#define EXACT 1 -#define ATLEAST 2 -#define MASK 3 -#define SMALLER 4 -#define SPECIAL 5 -#define NONE 6 + return valid; +} -struct sort_info { - EGLint Attribute; - EGLint MatchCriteria; - EGLint SortOrder; -}; -/* This encodes the info from Table 3.5 of the EGL spec, ordered by - * Sort Priority. +/** + * Return true if a config matches the criteria. This and + * _eglParseConfigAttribList together implement the algorithm + * described in "Selection of EGLConfigs". * - * XXX To do: EGL 1.2 attribs + * Note that attributes that are special (currently, only + * EGL_MATCH_NATIVE_PIXMAP) are ignored. */ -static struct sort_info SortInfo[] = { - { EGL_CONFIG_CAVEAT, EXACT, SPECIAL }, - { EGL_RED_SIZE, ATLEAST, SPECIAL }, - { EGL_GREEN_SIZE, ATLEAST, SPECIAL }, - { EGL_BLUE_SIZE, ATLEAST, SPECIAL }, - { EGL_ALPHA_SIZE, ATLEAST, SPECIAL }, - { EGL_BUFFER_SIZE, ATLEAST, SMALLER }, - { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER }, - { EGL_SAMPLES, ATLEAST, SMALLER }, - { EGL_DEPTH_SIZE, ATLEAST, SMALLER }, - { EGL_STENCIL_SIZE, ATLEAST, SMALLER }, - { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL }, - { EGL_CONFIG_ID, EXACT, SMALLER }, - { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE }, - { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE }, - { EGL_LEVEL, EXACT, NONE }, - { EGL_NATIVE_RENDERABLE, EXACT, NONE }, - { EGL_MAX_SWAP_INTERVAL, EXACT, NONE }, - { EGL_MIN_SWAP_INTERVAL, EXACT, NONE }, - { EGL_SURFACE_TYPE, MASK, NONE }, - { EGL_TRANSPARENT_TYPE, EXACT, NONE }, - { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE }, - { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE }, - { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE }, - { 0, 0, 0 } -}; +EGLBoolean +_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) +{ + EGLint attr, val, i; + EGLBoolean matched = EGL_TRUE; + + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + EGLint cmp; + if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) + continue; + + attr = _eglValidationTable[i].attr; + cmp = _eglGetConfigKey(criteria, attr); + if (cmp == EGL_DONT_CARE) + continue; + + val = _eglGetConfigKey(conf, attr); + switch (_eglValidationTable[i].criterion) { + case ATTRIB_CRITERION_EXACT: + if (val != cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_ATLEAST: + if (val < cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_MASK: + if ((val & cmp) != cmp) + matched = EGL_FALSE; + break; + case ATTRIB_CRITERION_SPECIAL: + /* ignored here */ + break; + default: + assert(0); + break; + } + + if (!matched) { +#ifndef DEBUG + /* only print the common errors when DEBUG is not defined */ + if (attr != EGL_RENDERABLE_TYPE) + break; +#endif + _eglLog(_EGL_DEBUG, + "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", + val, attr, cmp); + break; + } + } + return matched; +} + +static INLINE EGLBoolean +_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) +{ + if (_eglOffsetOfConfig(attr) < 0) + return EGL_FALSE; + + switch (attr) { + case EGL_MATCH_NATIVE_PIXMAP: + return EGL_FALSE; + case EGL_Y_INVERTED_NOK: + return conf->Display->Extensions.NOK_texture_from_pixmap; + default: + break; + } + + return EGL_TRUE; +} /** - * Return EGL_TRUE if the attributes of c meet or exceed the minimums - * specified by min. + * Initialize a criteria config from the given attribute list. + * Return EGL_FALSE if any of the attribute is invalid. */ -static EGLBoolean -_eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min) +EGLBoolean +_eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list) { - EGLint i; - for (i = 0; SortInfo[i].Attribute != 0; i++) { - const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute); - if (mv != EGL_DONT_CARE) { - const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute); - if (SortInfo[i].MatchCriteria == EXACT) { - if (cv != mv) { - return EGL_FALSE; - } - } - else if (SortInfo[i].MatchCriteria == ATLEAST) { - if (cv < mv) { - return EGL_FALSE; - } - } - else { - assert(SortInfo[i].MatchCriteria == MASK); - if ((mv & cv) != mv) { - return EGL_FALSE; - } - } + EGLint attr, val, i; + + /* reset to default values */ + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + attr = _eglValidationTable[i].attr; + val = _eglValidationTable[i].default_value; + _eglSetConfigKey(conf, attr, val); + } + + /* parse the list */ + for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { + attr = attrib_list[i]; + val = attrib_list[i + 1]; + + if (!_eglIsConfigAttribValid(conf, attr)) + return EGL_FALSE; + + _eglSetConfigKey(conf, attr, val); + } + + if (!_eglValidateConfig(conf, EGL_TRUE)) + return EGL_FALSE; + + /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ + if (conf->Level == EGL_DONT_CARE) + return EGL_FALSE; + + /* ignore other attributes when EGL_CONFIG_ID is given */ + if (conf->ConfigID > 0) { + for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { + attr = _eglValidationTable[i].attr; + if (attr != EGL_CONFIG_ID) + _eglSetConfigKey(conf, attr, EGL_DONT_CARE); } } + else { + if (!(conf->SurfaceType & EGL_WINDOW_BIT)) + conf->NativeVisualType = EGL_DONT_CARE; + + if (conf->TransparentType == EGL_NONE) { + conf->TransparentRedValue = EGL_DONT_CARE; + conf->TransparentGreenValue = EGL_DONT_CARE; + conf->TransparentBlueValue = EGL_DONT_CARE; + } + } + return EGL_TRUE; } /** - * Compare configs 'a' and 'b' and return -1 if a belongs before b, - * 1 if a belongs after b, or 0 if they're equal. - * Used by qsort(). + * Decide the ordering of conf1 and conf2, under the given criteria. + * When compare_id is true, this implements the algorithm described + * in "Sorting of EGLConfigs". When compare_id is false, + * EGL_CONFIG_ID is not compared. + * + * It returns a negative integer if conf1 is considered to come + * before conf2; a positive integer if conf2 is considered to come + * before conf1; zero if the ordering cannot be decided. + * + * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is + * ignored here. */ -static int -_eglCompareConfigs(const void *a, const void *b) +EGLint +_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, + const _EGLConfig *criteria, EGLBoolean compare_id) { - const _EGLConfig *aConfig = (const _EGLConfig *) a; - const _EGLConfig *bConfig = (const _EGLConfig *) b; + const EGLint compare_attribs[] = { + EGL_BUFFER_SIZE, + EGL_SAMPLE_BUFFERS, + EGL_SAMPLES, + EGL_DEPTH_SIZE, + EGL_STENCIL_SIZE, + EGL_ALPHA_MASK_SIZE, + }; + EGLint val1, val2; EGLint i; - for (i = 0; SortInfo[i].Attribute != 0; i++) { - const EGLint aVal = GET_CONFIG_ATTRIB(aConfig, SortInfo[i].Attribute); - const EGLint bVal = GET_CONFIG_ATTRIB(bConfig, SortInfo[i].Attribute); - if (SortInfo[i].SortOrder == SMALLER) { - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; - /* else, continue examining attribute values */ - } - else if (SortInfo[i].SortOrder == SPECIAL) { - if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) { - /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */ - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; + if (conf1 == conf2) + return 0; + + /* the enum values have the desired ordering */ + assert(EGL_NONE < EGL_SLOW_CONFIG); + assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); + val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; + if (val1) + return val1; + + /* the enum values have the desired ordering */ + assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); + val1 = conf1->ColorBufferType - conf2->ColorBufferType; + if (val1) + return val1; + + if (criteria) { + val1 = val2 = 0; + if (conf1->ColorBufferType == EGL_RGB_BUFFER) { + if (criteria->RedSize > 0) { + val1 += conf1->RedSize; + val2 += conf2->RedSize; } - else if (SortInfo[i].Attribute == EGL_RED_SIZE || - SortInfo[i].Attribute == EGL_GREEN_SIZE || - SortInfo[i].Attribute == EGL_BLUE_SIZE || - SortInfo[i].Attribute == EGL_ALPHA_SIZE) { - if (aVal > bVal) - return -1; - else if (aVal < bVal) - return 1; + if (criteria->GreenSize > 0) { + val1 += conf1->GreenSize; + val2 += conf2->GreenSize; } - else { - assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE); - if (aVal < bVal) - return -1; - else if (aVal > bVal) - return 1; + if (criteria->BlueSize > 0) { + val1 += conf1->BlueSize; + val2 += conf2->BlueSize; } } else { - assert(SortInfo[i].SortOrder == NONE); - /* continue examining attribute values */ + if (criteria->LuminanceSize > 0) { + val1 += conf1->LuminanceSize; + val2 += conf2->LuminanceSize; + } } + if (criteria->AlphaSize > 0) { + val1 += conf1->AlphaSize; + val2 += conf2->AlphaSize; + } + } + else { + /* assume the default criteria, which gives no specific ordering */ + val1 = val2 = 0; } - /* all attributes identical */ - return 0; + /* for color bits, larger one is preferred */ + if (val1 != val2) + return (val2 - val1); + + for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { + val1 = _eglGetConfigKey(conf1, compare_attribs[i]); + val2 = _eglGetConfigKey(conf2, compare_attribs[i]); + if (val1 != val2) + return (val1 - val2); + } + + /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ + + return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; +} + + +static INLINE +void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) +{ + const _EGLConfig *tmp = *conf1; + *conf1 = *conf2; + *conf2 = tmp; +} + + +/** + * Quick sort an array of configs. This differs from the standard + * qsort() in that the compare function accepts an additional + * argument. + */ +void +_eglSortConfigs(const _EGLConfig **configs, EGLint count, + EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, + void *), + void *priv_data) +{ + const EGLint pivot = 0; + EGLint i, j; + + if (count <= 1) + return; + + _eglSwapConfigs(&configs[pivot], &configs[count / 2]); + i = 1; + j = count - 1; + do { + while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) + i++; + while (compare(configs[j], configs[pivot], priv_data) > 0) + j--; + if (i < j) { + _eglSwapConfigs(&configs[i], &configs[j]); + i++; + j--; + } + else if (i == j) { + i++; + j--; + break; + } + } while (i <= j); + _eglSwapConfigs(&configs[pivot], &configs[j]); + + _eglSortConfigs(configs, j, compare, priv_data); + _eglSortConfigs(configs + i, count - i, compare, priv_data); +} + + +static int +_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, + void *priv_data) +{ + const _EGLConfig *criteria = (const _EGLConfig *) priv_data; + return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); } @@ -324,33 +680,25 @@ _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, _EGLConfig **configList, criteria; EGLint i, count; - /* parse the attrib_list to initialize criteria */ - if (!_eglParseConfigAttribs(&criteria, attrib_list)) { - return EGL_FALSE; - } - - /* allocate array of config pointers */ - configList = (_EGLConfig **) malloc(config_size * sizeof(_EGLConfig *)); - if (!configList) { - _eglError(EGL_BAD_CONFIG, "eglChooseConfig(out of memory)"); - return EGL_FALSE; - } - - /* make array of pointers to qualifying configs */ - for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) { - if (_eglConfigQualifies(disp->Configs[i], &criteria)) { - configList[count++] = disp->Configs[i]; - } - } - - /* sort array of pointers */ - qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs); - - /* copy config handles to output array */ - if (configs) { - for (i = 0; i < count; i++) { - configs[i] = configList[i]->Handle; - } + if (!num_configs) + return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); + + _eglInitConfig(&criteria, disp, 0); + if (!_eglParseConfigAttribList(&criteria, attrib_list)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); + + configList = (_EGLConfig **) _eglFilterArray(disp->Configs, &count, + (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria); + if (!configList) + return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); + + /* perform sorting of configs */ + if (configs && count) { + _eglSortConfigs((const _EGLConfig **) configList, count, + _eglFallbackCompare, (void *) &criteria); + count = MIN2(count, config_size); + for (i = 0; i < count; i++) + configs[i] = _eglGetConfigHandle(configList[i]); } free(configList); @@ -368,18 +716,25 @@ EGLBoolean _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, EGLint attribute, EGLint *value) { - const EGLint k = attribute - FIRST_ATTRIB; - if (k >= 0 && k < MAX_ATTRIBS) { - *value = conf->Attrib[k]; - return EGL_TRUE; - } - else { - _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); - return EGL_FALSE; - } + if (!_eglIsConfigAttribValid(conf, attribute)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); + + *value = _eglGetConfigKey(conf, attribute); + return EGL_TRUE; } +static EGLBoolean +_eglFlattenConfig(void *elem, void *buffer) +{ + _EGLConfig *conf = (_EGLConfig *) elem; + EGLConfig *handle = (EGLConfig *) buffer; + *handle = _eglGetConfigHandle(conf); + return EGL_TRUE; +} + /** * Fallback for eglGetConfigs. */ @@ -387,17 +742,11 @@ EGLBoolean _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, EGLint config_size, EGLint *num_config) { - if (configs) { - EGLint i; - *num_config = MIN2(disp->NumConfigs, config_size); - for (i = 0; i < *num_config; i++) { - configs[i] = disp->Configs[i]->Handle; - } - } - else { - /* just return total number of supported configs */ - *num_config = disp->NumConfigs; - } + if (!num_config) + return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); + + *num_config = _eglFlattenArray(disp->Configs, (void *) configs, + sizeof(configs[0]), config_size, _eglFlattenConfig); return EGL_TRUE; }