| /** |
| * EGL Configuration (pixel format) functions. |
| */ |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <assert.h> |
| #include "eglconfig.h" |
| #include "egldisplay.h" |
| #include "egldriver.h" |
| #include "eglglobals.h" |
| #include "egllog.h" |
| |
| |
| #define MIN2(A, B) (((A) < (B)) ? (A) : (B)) |
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) |
| |
| |
| /** |
| * 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) |
| { |
| memset(config, 0, sizeof(*config)); |
| |
| /* some attributes take non-zero default values */ |
| SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id); |
| SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_NONE); |
| SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE); |
| SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_NONE); |
| #ifdef EGL_VERSION_1_2 |
| SET_CONFIG_ATTRIB(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER); |
| #endif /* EGL_VERSION_1_2 */ |
| } |
| |
| |
| /** |
| * 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 |
| _eglAddConfig(_EGLDisplay *dpy, _EGLConfig *conf) |
| { |
| _EGLConfig **configs; |
| |
| /* sanity check */ |
| assert(GET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID) > 0); |
| |
| configs = dpy->Configs; |
| if (dpy->NumConfigs >= dpy->MaxConfigs) { |
| EGLint new_size = dpy->MaxConfigs + 16; |
| assert(dpy->NumConfigs < new_size); |
| |
| configs = realloc(dpy->Configs, new_size * sizeof(dpy->Configs[0])); |
| if (!configs) |
| return (EGLConfig) NULL; |
| |
| dpy->Configs = configs; |
| dpy->MaxConfigs = new_size; |
| } |
| |
| conf->Display = dpy; |
| dpy->Configs[dpy->NumConfigs++] = conf; |
| |
| return (EGLConfig) conf; |
| } |
| |
| |
| #ifndef _EGL_SKIP_HANDLE_CHECK |
| |
| |
| EGLBoolean |
| _eglCheckConfigHandle(EGLConfig config, _EGLDisplay *dpy) |
| { |
| EGLint num_configs = (dpy) ? dpy->NumConfigs : 0; |
| EGLint i; |
| |
| for (i = 0; i < num_configs; i++) { |
| _EGLConfig *conf = dpy->Configs[i]; |
| if (conf == (_EGLConfig *) config) { |
| assert(conf->Display == dpy); |
| break; |
| } |
| } |
| return (i < num_configs); |
| } |
| |
| |
| #endif /* _EGL_SKIP_HANDLE_CHECK */ |
| |
| |
| 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[] = |
| { |
| { 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 }, |
| /* these are not real attributes */ |
| { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, |
| ATTRIB_CRITERION_SPECIAL, |
| EGL_NONE }, |
| { EGL_PRESERVED_RESOURCES, ATTRIB_TYPE_PSEUDO, |
| ATTRIB_CRITERION_IGNORE, |
| 0 }, |
| { EGL_NONE, ATTRIB_TYPE_PSEUDO, |
| ATTRIB_CRITERION_IGNORE, |
| 0 } |
| }; |
| |
| |
| /** |
| * 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 |
| _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) |
| { |
| EGLint i, attr, val; |
| EGLBoolean valid = EGL_TRUE; |
| EGLint red_size = 0, green_size = 0, blue_size = 0, luminance_size = 0; |
| EGLint alpha_size = 0, buffer_size = 0; |
| |
| /* all attributes should have been listed */ |
| assert(ARRAY_SIZE(_eglValidationTable) == _EGL_CONFIG_NUM_ATTRIBS); |
| |
| /* check attributes by their types */ |
| for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { |
| EGLint mask; |
| |
| attr = _eglValidationTable[i].attr; |
| val = GET_CONFIG_ATTRIB(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) |
| valid = EGL_FALSE; |
| break; |
| case EGL_RED_SIZE: |
| red_size = val; |
| break; |
| case EGL_GREEN_SIZE: |
| green_size = val; |
| break; |
| case EGL_BLUE_SIZE: |
| blue_size = val; |
| break; |
| case EGL_LUMINANCE_SIZE: |
| luminance_size = val; |
| break; |
| case EGL_ALPHA_SIZE: |
| alpha_size = val; |
| break; |
| case EGL_BUFFER_SIZE: |
| buffer_size = val; |
| break; |
| } |
| if (val < 0) |
| valid = 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_SCREEN_BIT_MESA | /* XXX should check the extension */ |
| EGL_VG_COLORSPACE_LINEAR_BIT | |
| EGL_VG_ALPHA_FORMAT_PRE_BIT | |
| EGL_MULTISAMPLE_RESOLVE_BOX_BIT | |
| EGL_SWAP_BEHAVIOR_PRESERVED_BIT; |
| 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; |
| } |
| 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; |
| } |
| |
| 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; |
| } |
| if (!valid) |
| break; |
| } |
| |
| /* any invalid attribute value should have been catched */ |
| if (!valid || for_matching) |
| return valid; |
| |
| /* now check for conflicting attribute values */ |
| |
| switch (GET_CONFIG_ATTRIB(conf, EGL_COLOR_BUFFER_TYPE)) { |
| case EGL_RGB_BUFFER: |
| if (luminance_size) |
| valid = EGL_FALSE; |
| if (red_size + green_size + blue_size + alpha_size != buffer_size) |
| valid = EGL_FALSE; |
| break; |
| case EGL_LUMINANCE_BUFFER: |
| if (red_size || green_size || blue_size) |
| valid = EGL_FALSE; |
| if (luminance_size + alpha_size != buffer_size) |
| valid = EGL_FALSE; |
| break; |
| } |
| |
| val = GET_CONFIG_ATTRIB(conf, EGL_SAMPLE_BUFFERS); |
| if (!val && GET_CONFIG_ATTRIB(conf, EGL_SAMPLES)) |
| valid = EGL_FALSE; |
| |
| val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); |
| if (!(val & EGL_WINDOW_BIT)) { |
| if (GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_ID) != 0 || |
| GET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE) != EGL_NONE) |
| valid = EGL_FALSE; |
| } |
| if (!(val & EGL_PBUFFER_BIT)) { |
| if (GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGB) || |
| GET_CONFIG_ATTRIB(conf, EGL_BIND_TO_TEXTURE_RGBA)) |
| valid = EGL_FALSE; |
| } |
| |
| return valid; |
| } |
| |
| |
| /** |
| * Return true if a config matches the criteria. This and |
| * _eglParseConfigAttribList together implement the algorithm |
| * described in "Selection of EGLConfigs". |
| * |
| * Note that attributes that are special (currently, only |
| * EGL_MATCH_NATIVE_PIXMAP) are ignored. |
| */ |
| 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 = GET_CONFIG_ATTRIB(criteria, attr); |
| if (cmp == EGL_DONT_CARE) |
| continue; |
| |
| val = GET_CONFIG_ATTRIB(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) |
| break; |
| } |
| |
| return matched; |
| } |
| |
| |
| /** |
| * Initialize a criteria config from the given attribute list. |
| * Return EGL_FALSE if any of the attribute is invalid. |
| */ |
| EGLBoolean |
| _eglParseConfigAttribList(_EGLConfig *conf, const EGLint *attrib_list) |
| { |
| EGLint attr, val, i; |
| EGLint config_id = 0, level = 0; |
| EGLBoolean has_native_visual_type = EGL_FALSE; |
| EGLBoolean has_transparent_color = EGL_FALSE; |
| |
| /* reset to default values */ |
| for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { |
| attr = _eglValidationTable[i].attr; |
| val = _eglValidationTable[i].default_value; |
| SET_CONFIG_ATTRIB(conf, attr, val); |
| } |
| |
| /* parse the list */ |
| for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { |
| EGLint idx; |
| |
| attr = attrib_list[i]; |
| val = attrib_list[i + 1]; |
| |
| idx = _eglIndexConfig(conf, attr); |
| if (idx < 0) |
| return EGL_FALSE; |
| conf->Storage[idx] = val; |
| |
| /* rememeber some attributes for post-processing */ |
| switch (attr) { |
| case EGL_CONFIG_ID: |
| config_id = val; |
| break; |
| case EGL_LEVEL: |
| level = val; |
| break; |
| case EGL_NATIVE_VISUAL_TYPE: |
| has_native_visual_type = EGL_TRUE; |
| break; |
| case EGL_TRANSPARENT_RED_VALUE: |
| case EGL_TRANSPARENT_GREEN_VALUE: |
| case EGL_TRANSPARENT_BLUE_VALUE: |
| has_transparent_color = EGL_TRUE; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (!_eglValidateConfig(conf, EGL_TRUE)) |
| return EGL_FALSE; |
| |
| /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ |
| if (level == EGL_DONT_CARE) |
| return EGL_FALSE; |
| |
| /* ignore other attributes when EGL_CONFIG_ID is given */ |
| if (config_id > 0) { |
| _eglResetConfigKeys(conf, EGL_DONT_CARE); |
| SET_CONFIG_ATTRIB(conf, EGL_CONFIG_ID, config_id); |
| } |
| else { |
| if (has_native_visual_type) { |
| val = GET_CONFIG_ATTRIB(conf, EGL_SURFACE_TYPE); |
| if (!(val & EGL_WINDOW_BIT)) |
| SET_CONFIG_ATTRIB(conf, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE); |
| } |
| |
| if (has_transparent_color) { |
| val = GET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_TYPE); |
| if (val == EGL_NONE) { |
| SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_RED_VALUE, |
| EGL_DONT_CARE); |
| SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_GREEN_VALUE, |
| EGL_DONT_CARE); |
| SET_CONFIG_ATTRIB(conf, EGL_TRANSPARENT_BLUE_VALUE, |
| EGL_DONT_CARE); |
| } |
| } |
| } |
| |
| return EGL_TRUE; |
| } |
| |
| |
| /** |
| * 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. |
| */ |
| EGLint |
| _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, |
| const _EGLConfig *criteria, EGLBoolean compare_id) |
| { |
| 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; |
| EGLBoolean rgb_buffer; |
| EGLint i; |
| |
| 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 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_CAVEAT); |
| val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_CAVEAT); |
| if (val1 != val2) |
| return (val1 - val2); |
| |
| /* the enum values have the desired ordering */ |
| assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); |
| val1 = GET_CONFIG_ATTRIB(conf1, EGL_COLOR_BUFFER_TYPE); |
| val2 = GET_CONFIG_ATTRIB(conf2, EGL_COLOR_BUFFER_TYPE); |
| if (val1 != val2) |
| return (val1 - val2); |
| rgb_buffer = (val1 == EGL_RGB_BUFFER); |
| |
| if (criteria) { |
| val1 = val2 = 0; |
| if (rgb_buffer) { |
| if (GET_CONFIG_ATTRIB(criteria, EGL_RED_SIZE) > 0) { |
| val1 += GET_CONFIG_ATTRIB(conf1, EGL_RED_SIZE); |
| val2 += GET_CONFIG_ATTRIB(conf2, EGL_RED_SIZE); |
| } |
| if (GET_CONFIG_ATTRIB(criteria, EGL_GREEN_SIZE) > 0) { |
| val1 += GET_CONFIG_ATTRIB(conf1, EGL_GREEN_SIZE); |
| val2 += GET_CONFIG_ATTRIB(conf2, EGL_GREEN_SIZE); |
| } |
| if (GET_CONFIG_ATTRIB(criteria, EGL_BLUE_SIZE) > 0) { |
| val1 += GET_CONFIG_ATTRIB(conf1, EGL_BLUE_SIZE); |
| val2 += GET_CONFIG_ATTRIB(conf2, EGL_BLUE_SIZE); |
| } |
| } |
| else { |
| if (GET_CONFIG_ATTRIB(criteria, EGL_LUMINANCE_SIZE) > 0) { |
| val1 += GET_CONFIG_ATTRIB(conf1, EGL_LUMINANCE_SIZE); |
| val2 += GET_CONFIG_ATTRIB(conf2, EGL_LUMINANCE_SIZE); |
| } |
| } |
| if (GET_CONFIG_ATTRIB(criteria, EGL_ALPHA_SIZE) > 0) { |
| val1 += GET_CONFIG_ATTRIB(conf1, EGL_ALPHA_SIZE); |
| val2 += GET_CONFIG_ATTRIB(conf2, EGL_ALPHA_SIZE); |
| } |
| } |
| else { |
| /* assume the default criteria, which gives no specific ordering */ |
| val1 = val2 = 0; |
| } |
| |
| /* for color bits, larger one is preferred */ |
| if (val1 != val2) |
| return (val2 - val1); |
| |
| for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { |
| val1 = GET_CONFIG_ATTRIB(conf1, compare_attribs[i]); |
| val2 = GET_CONFIG_ATTRIB(conf2, compare_attribs[i]); |
| if (val1 != val2) |
| return (val1 - val2); |
| } |
| |
| /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ |
| |
| if (compare_id) { |
| val1 = GET_CONFIG_ATTRIB(conf1, EGL_CONFIG_ID); |
| val2 = GET_CONFIG_ATTRIB(conf2, EGL_CONFIG_ID); |
| assert(val1 != val2); |
| } |
| else { |
| val1 = val2 = 0; |
| } |
| |
| return (val1 - val2); |
| } |
| |
| |
| 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); |
| } |
| |
| |
| /** |
| * Typical fallback routine for eglChooseConfig |
| */ |
| EGLBoolean |
| _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, |
| EGLConfig *configs, EGLint config_size, EGLint *num_configs) |
| { |
| _EGLConfig **configList, criteria; |
| EGLint i, count; |
| |
| if (!num_configs) |
| return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); |
| |
| _eglInitConfig(&criteria, 0); |
| if (!_eglParseConfigAttribList(&criteria, attrib_list)) |
| return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); |
| |
| /* allocate array of config pointers */ |
| configList = (_EGLConfig **) |
| malloc(disp->NumConfigs * sizeof(_EGLConfig *)); |
| if (!configList) |
| return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); |
| |
| /* perform selection of configs */ |
| count = 0; |
| for (i = 0; i < disp->NumConfigs; i++) { |
| if (_eglMatchConfig(disp->Configs[i], &criteria)) |
| configList[count++] = disp->Configs[i]; |
| } |
| |
| /* 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); |
| |
| *num_configs = count; |
| |
| return EGL_TRUE; |
| } |
| |
| |
| static INLINE EGLBoolean |
| _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) |
| { |
| if (_eglIndexConfig(conf, attr) < 0) |
| return EGL_FALSE; |
| |
| /* there are some holes in the range */ |
| switch (attr) { |
| case EGL_PRESERVED_RESOURCES: |
| case EGL_NONE: |
| #ifdef EGL_VERSION_1_4 |
| case EGL_MATCH_NATIVE_PIXMAP: |
| #endif |
| return EGL_FALSE; |
| default: |
| break; |
| } |
| |
| return EGL_TRUE; |
| } |
| |
| |
| /** |
| * Fallback for eglGetConfigAttrib. |
| */ |
| EGLBoolean |
| _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, |
| EGLint attribute, EGLint *value) |
| { |
| if (!_eglIsConfigAttribValid(conf, attribute)) |
| return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); |
| if (!value) |
| return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); |
| |
| *value = GET_CONFIG_ATTRIB(conf, attribute); |
| return EGL_TRUE; |
| } |
| |
| |
| /** |
| * Fallback for eglGetConfigs. |
| */ |
| EGLBoolean |
| _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, |
| EGLint config_size, EGLint *num_config) |
| { |
| if (!num_config) |
| return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); |
| |
| if (configs) { |
| EGLint i; |
| *num_config = MIN2(disp->NumConfigs, config_size); |
| for (i = 0; i < *num_config; i++) |
| configs[i] = _eglGetConfigHandle(disp->Configs[i]); |
| } |
| else { |
| /* just return total number of supported configs */ |
| *num_config = disp->NumConfigs; |
| } |
| |
| return EGL_TRUE; |
| } |