eglconfig.c revision 3464ebd5
13464ebd5Sriastradh/************************************************************************** 23464ebd5Sriastradh * 33464ebd5Sriastradh * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 43464ebd5Sriastradh * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 53464ebd5Sriastradh * Copyright 2010-2011 LunarG, Inc. 63464ebd5Sriastradh * All Rights Reserved. 73464ebd5Sriastradh * 83464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 93464ebd5Sriastradh * copy of this software and associated documentation files (the 103464ebd5Sriastradh * "Software"), to deal in the Software without restriction, including 113464ebd5Sriastradh * without limitation the rights to use, copy, modify, merge, publish, 123464ebd5Sriastradh * distribute, sub license, and/or sell copies of the Software, and to 133464ebd5Sriastradh * permit persons to whom the Software is furnished to do so, subject to 143464ebd5Sriastradh * the following conditions: 153464ebd5Sriastradh * 163464ebd5Sriastradh * The above copyright notice and this permission notice (including the 173464ebd5Sriastradh * next paragraph) shall be included in all copies or substantial portions 183464ebd5Sriastradh * of the Software. 193464ebd5Sriastradh * 203464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 213464ebd5Sriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 223464ebd5Sriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 233464ebd5Sriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 243464ebd5Sriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 253464ebd5Sriastradh * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 263464ebd5Sriastradh * DEALINGS IN THE SOFTWARE. 273464ebd5Sriastradh * 283464ebd5Sriastradh **************************************************************************/ 293464ebd5Sriastradh 303464ebd5Sriastradh 314a49301eSmrg/** 324a49301eSmrg * EGL Configuration (pixel format) functions. 334a49301eSmrg */ 344a49301eSmrg 354a49301eSmrg 364a49301eSmrg#include <stdlib.h> 374a49301eSmrg#include <string.h> 384a49301eSmrg#include <assert.h> 394a49301eSmrg#include "eglconfig.h" 404a49301eSmrg#include "egldisplay.h" 41cdc920a0Smrg#include "eglcurrent.h" 424a49301eSmrg#include "egllog.h" 434a49301eSmrg 444a49301eSmrg 454a49301eSmrg#define MIN2(A, B) (((A) < (B)) ? (A) : (B)) 464a49301eSmrg 474a49301eSmrg 484a49301eSmrg/** 494a49301eSmrg * Init the given _EGLconfig to default values. 504a49301eSmrg * \param id the configuration's ID. 514a49301eSmrg * 524a49301eSmrg * Note that id must be positive for the config to be valid. 534a49301eSmrg * It is also recommended that when there are N configs, their 544a49301eSmrg * IDs are from 1 to N respectively. 554a49301eSmrg */ 564a49301eSmrgvoid 573464ebd5Sriastradh_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id) 584a49301eSmrg{ 593464ebd5Sriastradh memset(conf, 0, sizeof(*conf)); 604a49301eSmrg 613464ebd5Sriastradh conf->Display = dpy; 62cdc920a0Smrg 634a49301eSmrg /* some attributes take non-zero default values */ 643464ebd5Sriastradh conf->ConfigID = id; 653464ebd5Sriastradh conf->ConfigCaveat = EGL_NONE; 663464ebd5Sriastradh conf->TransparentType = EGL_NONE; 673464ebd5Sriastradh conf->NativeVisualType = EGL_NONE; 683464ebd5Sriastradh conf->ColorBufferType = EGL_RGB_BUFFER; 694a49301eSmrg} 704a49301eSmrg 714a49301eSmrg 724a49301eSmrg/** 733464ebd5Sriastradh * Link a config to its display and return the handle of the link. 744a49301eSmrg * The handle can be passed to client directly. 754a49301eSmrg * 764a49301eSmrg * Note that we just save the ptr to the config (we don't copy the config). 774a49301eSmrg */ 783464ebd5SriastradhPUBLIC EGLConfig 793464ebd5Sriastradh_eglLinkConfig(_EGLConfig *conf) 804a49301eSmrg{ 813464ebd5Sriastradh _EGLDisplay *dpy = conf->Display; 824a49301eSmrg 834a49301eSmrg /* sanity check */ 843464ebd5Sriastradh assert(dpy && conf->ConfigID > 0); 854a49301eSmrg 863464ebd5Sriastradh if (!dpy->Configs) { 873464ebd5Sriastradh dpy->Configs = _eglCreateArray("Config", 16); 883464ebd5Sriastradh if (!dpy->Configs) 894a49301eSmrg return (EGLConfig) NULL; 904a49301eSmrg } 914a49301eSmrg 923464ebd5Sriastradh _eglAppendArray(dpy->Configs, (void *) conf); 934a49301eSmrg 944a49301eSmrg return (EGLConfig) conf; 954a49301eSmrg} 964a49301eSmrg 974a49301eSmrg 983464ebd5Sriastradh/** 993464ebd5Sriastradh * Lookup a handle to find the linked config. 1003464ebd5Sriastradh * Return NULL if the handle has no corresponding linked config. 1013464ebd5Sriastradh */ 1023464ebd5Sriastradh_EGLConfig * 1033464ebd5Sriastradh_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy) 1044a49301eSmrg{ 1053464ebd5Sriastradh _EGLConfig *conf; 1064a49301eSmrg 1073464ebd5Sriastradh if (!dpy) 1083464ebd5Sriastradh return NULL; 1093464ebd5Sriastradh 1103464ebd5Sriastradh conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config); 1113464ebd5Sriastradh if (conf) 1123464ebd5Sriastradh assert(conf->Display == dpy); 1133464ebd5Sriastradh 1143464ebd5Sriastradh return conf; 1154a49301eSmrg} 1164a49301eSmrg 1174a49301eSmrg 1184a49301eSmrgenum { 1194a49301eSmrg /* types */ 1204a49301eSmrg ATTRIB_TYPE_INTEGER, 1214a49301eSmrg ATTRIB_TYPE_BOOLEAN, 1224a49301eSmrg ATTRIB_TYPE_BITMASK, 1234a49301eSmrg ATTRIB_TYPE_ENUM, 1244a49301eSmrg ATTRIB_TYPE_PSEUDO, /* non-queryable */ 1254a49301eSmrg ATTRIB_TYPE_PLATFORM, /* platform-dependent */ 1264a49301eSmrg /* criteria */ 1274a49301eSmrg ATTRIB_CRITERION_EXACT, 1284a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1294a49301eSmrg ATTRIB_CRITERION_MASK, 1304a49301eSmrg ATTRIB_CRITERION_SPECIAL, 131cdc920a0Smrg ATTRIB_CRITERION_IGNORE 1324a49301eSmrg}; 1334a49301eSmrg 1344a49301eSmrg 1354a49301eSmrg/* EGL spec Table 3.1 and 3.4 */ 1364a49301eSmrgstatic const struct { 1374a49301eSmrg EGLint attr; 1384a49301eSmrg EGLint type; 1394a49301eSmrg EGLint criterion; 1404a49301eSmrg EGLint default_value; 1414a49301eSmrg} _eglValidationTable[] = 1424a49301eSmrg{ 1433464ebd5Sriastradh /* core */ 1444a49301eSmrg { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, 1454a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1464a49301eSmrg 0 }, 1474a49301eSmrg { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, 1484a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1494a49301eSmrg 0 }, 1504a49301eSmrg { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, 1514a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1524a49301eSmrg 0 }, 1534a49301eSmrg { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, 1544a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1554a49301eSmrg 0 }, 1564a49301eSmrg { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, 1574a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1584a49301eSmrg 0 }, 1594a49301eSmrg { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, 1604a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1614a49301eSmrg 0 }, 1624a49301eSmrg { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, 1634a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1644a49301eSmrg 0 }, 1654a49301eSmrg { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, 1664a49301eSmrg ATTRIB_CRITERION_EXACT, 1674a49301eSmrg EGL_DONT_CARE }, 1684a49301eSmrg { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, 1694a49301eSmrg ATTRIB_CRITERION_EXACT, 1704a49301eSmrg EGL_DONT_CARE }, 1714a49301eSmrg { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, 1724a49301eSmrg ATTRIB_CRITERION_EXACT, 1734a49301eSmrg EGL_RGB_BUFFER }, 1744a49301eSmrg { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, 1754a49301eSmrg ATTRIB_CRITERION_EXACT, 1764a49301eSmrg EGL_DONT_CARE }, 1774a49301eSmrg { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, 1784a49301eSmrg ATTRIB_CRITERION_EXACT, 1794a49301eSmrg EGL_DONT_CARE }, 1804a49301eSmrg { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, 1814a49301eSmrg ATTRIB_CRITERION_MASK, 1824a49301eSmrg 0 }, 1834a49301eSmrg { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, 1844a49301eSmrg ATTRIB_CRITERION_ATLEAST, 1854a49301eSmrg 0 }, 1864a49301eSmrg { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, 1874a49301eSmrg ATTRIB_CRITERION_EXACT, 1884a49301eSmrg 0 }, 1894a49301eSmrg { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, 1904a49301eSmrg ATTRIB_CRITERION_IGNORE, 1914a49301eSmrg 0 }, 1924a49301eSmrg { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, 1934a49301eSmrg ATTRIB_CRITERION_IGNORE, 1944a49301eSmrg 0 }, 1954a49301eSmrg { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, 1964a49301eSmrg ATTRIB_CRITERION_IGNORE, 1974a49301eSmrg 0 }, 1984a49301eSmrg { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 1994a49301eSmrg ATTRIB_CRITERION_EXACT, 2004a49301eSmrg EGL_DONT_CARE }, 2014a49301eSmrg { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 2024a49301eSmrg ATTRIB_CRITERION_EXACT, 2034a49301eSmrg EGL_DONT_CARE }, 2044a49301eSmrg { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, 2054a49301eSmrg ATTRIB_CRITERION_EXACT, 2064a49301eSmrg EGL_DONT_CARE }, 2074a49301eSmrg { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, 2084a49301eSmrg ATTRIB_CRITERION_IGNORE, 2094a49301eSmrg 0 }, 2104a49301eSmrg { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, 2114a49301eSmrg ATTRIB_CRITERION_EXACT, 2124a49301eSmrg EGL_DONT_CARE }, 2134a49301eSmrg { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, 2144a49301eSmrg ATTRIB_CRITERION_MASK, 2154a49301eSmrg EGL_OPENGL_ES_BIT }, 2164a49301eSmrg { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, 2174a49301eSmrg ATTRIB_CRITERION_ATLEAST, 2184a49301eSmrg 0 }, 2194a49301eSmrg { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, 2204a49301eSmrg ATTRIB_CRITERION_ATLEAST, 2214a49301eSmrg 0 }, 2224a49301eSmrg { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, 2234a49301eSmrg ATTRIB_CRITERION_ATLEAST, 2244a49301eSmrg 0 }, 2254a49301eSmrg { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, 2264a49301eSmrg ATTRIB_CRITERION_MASK, 2274a49301eSmrg EGL_WINDOW_BIT }, 2284a49301eSmrg { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, 2294a49301eSmrg ATTRIB_CRITERION_EXACT, 2304a49301eSmrg EGL_NONE }, 2314a49301eSmrg { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, 2324a49301eSmrg ATTRIB_CRITERION_EXACT, 2334a49301eSmrg EGL_DONT_CARE }, 2344a49301eSmrg { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, 2354a49301eSmrg ATTRIB_CRITERION_EXACT, 2364a49301eSmrg EGL_DONT_CARE }, 2374a49301eSmrg { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, 2384a49301eSmrg ATTRIB_CRITERION_EXACT, 2394a49301eSmrg EGL_DONT_CARE }, 2404a49301eSmrg { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, 2414a49301eSmrg ATTRIB_CRITERION_SPECIAL, 2424a49301eSmrg EGL_NONE }, 2433464ebd5Sriastradh /* extensions */ 2443464ebd5Sriastradh { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, 2453464ebd5Sriastradh ATTRIB_CRITERION_EXACT, 2463464ebd5Sriastradh EGL_DONT_CARE } 2474a49301eSmrg}; 2484a49301eSmrg 2494a49301eSmrg 2504a49301eSmrg/** 2514a49301eSmrg * Return true if a config is valid. When for_matching is true, 2524a49301eSmrg * EGL_DONT_CARE is accepted as a valid attribute value, and checks 2534a49301eSmrg * for conflicting attribute values are skipped. 2544a49301eSmrg * 2554a49301eSmrg * Note that some attributes are platform-dependent and are not 2564a49301eSmrg * checked. 2574a49301eSmrg */ 2584a49301eSmrgEGLBoolean 2594a49301eSmrg_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) 2604a49301eSmrg{ 2614a49301eSmrg EGLint i, attr, val; 2624a49301eSmrg EGLBoolean valid = EGL_TRUE; 2634a49301eSmrg 2644a49301eSmrg /* check attributes by their types */ 2654a49301eSmrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 2664a49301eSmrg EGLint mask; 2674a49301eSmrg 2684a49301eSmrg attr = _eglValidationTable[i].attr; 2693464ebd5Sriastradh val = _eglGetConfigKey(conf, attr); 2704a49301eSmrg 2714a49301eSmrg switch (_eglValidationTable[i].type) { 2724a49301eSmrg case ATTRIB_TYPE_INTEGER: 2734a49301eSmrg switch (attr) { 2744a49301eSmrg case EGL_CONFIG_ID: 2754a49301eSmrg /* config id must be positive */ 2764a49301eSmrg if (val <= 0) 2774a49301eSmrg valid = EGL_FALSE; 2784a49301eSmrg break; 2794a49301eSmrg case EGL_SAMPLE_BUFFERS: 2804a49301eSmrg /* there can be at most 1 sample buffer */ 2813464ebd5Sriastradh if (val > 1 || val < 0) 2824a49301eSmrg valid = EGL_FALSE; 2834a49301eSmrg break; 2843464ebd5Sriastradh default: 2853464ebd5Sriastradh if (val < 0) 2863464ebd5Sriastradh valid = EGL_FALSE; 2874a49301eSmrg break; 2884a49301eSmrg } 2894a49301eSmrg break; 2904a49301eSmrg case ATTRIB_TYPE_BOOLEAN: 2914a49301eSmrg if (val != EGL_TRUE && val != EGL_FALSE) 2924a49301eSmrg valid = EGL_FALSE; 2934a49301eSmrg break; 2944a49301eSmrg case ATTRIB_TYPE_ENUM: 2954a49301eSmrg switch (attr) { 2964a49301eSmrg case EGL_CONFIG_CAVEAT: 2974a49301eSmrg if (val != EGL_NONE && val != EGL_SLOW_CONFIG && 2984a49301eSmrg val != EGL_NON_CONFORMANT_CONFIG) 2994a49301eSmrg valid = EGL_FALSE; 3004a49301eSmrg break; 3014a49301eSmrg case EGL_TRANSPARENT_TYPE: 3024a49301eSmrg if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) 3034a49301eSmrg valid = EGL_FALSE; 3044a49301eSmrg break; 3054a49301eSmrg case EGL_COLOR_BUFFER_TYPE: 3064a49301eSmrg if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) 3074a49301eSmrg valid = EGL_FALSE; 3084a49301eSmrg break; 3094a49301eSmrg default: 3104a49301eSmrg assert(0); 3114a49301eSmrg break; 3124a49301eSmrg } 3134a49301eSmrg break; 3144a49301eSmrg case ATTRIB_TYPE_BITMASK: 3154a49301eSmrg switch (attr) { 3164a49301eSmrg case EGL_SURFACE_TYPE: 3174a49301eSmrg mask = EGL_PBUFFER_BIT | 3184a49301eSmrg EGL_PIXMAP_BIT | 3194a49301eSmrg EGL_WINDOW_BIT | 3204a49301eSmrg EGL_VG_COLORSPACE_LINEAR_BIT | 3214a49301eSmrg EGL_VG_ALPHA_FORMAT_PRE_BIT | 3224a49301eSmrg EGL_MULTISAMPLE_RESOLVE_BOX_BIT | 3234a49301eSmrg EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 3243464ebd5Sriastradh#ifdef EGL_MESA_screen_surface 325cdc920a0Smrg if (conf->Display->Extensions.MESA_screen_surface) 326cdc920a0Smrg mask |= EGL_SCREEN_BIT_MESA; 3273464ebd5Sriastradh#endif 3284a49301eSmrg break; 3294a49301eSmrg case EGL_RENDERABLE_TYPE: 3304a49301eSmrg case EGL_CONFORMANT: 3314a49301eSmrg mask = EGL_OPENGL_ES_BIT | 3324a49301eSmrg EGL_OPENVG_BIT | 3334a49301eSmrg EGL_OPENGL_ES2_BIT | 3344a49301eSmrg EGL_OPENGL_BIT; 3354a49301eSmrg break; 3364a49301eSmrg default: 3374a49301eSmrg assert(0); 3384a49301eSmrg break; 3394a49301eSmrg } 3404a49301eSmrg if (val & ~mask) 3414a49301eSmrg valid = EGL_FALSE; 3424a49301eSmrg break; 3434a49301eSmrg case ATTRIB_TYPE_PLATFORM: 3444a49301eSmrg /* unable to check platform-dependent attributes here */ 3454a49301eSmrg break; 3464a49301eSmrg case ATTRIB_TYPE_PSEUDO: 3474a49301eSmrg /* pseudo attributes should not be set */ 3484a49301eSmrg if (val != 0) 3494a49301eSmrg valid = EGL_FALSE; 3504a49301eSmrg break; 3514a49301eSmrg default: 3524a49301eSmrg assert(0); 3534a49301eSmrg break; 3544a49301eSmrg } 3554a49301eSmrg 3564a49301eSmrg if (!valid && for_matching) { 3574a49301eSmrg /* accept EGL_DONT_CARE as a valid value */ 3584a49301eSmrg if (val == EGL_DONT_CARE) 3594a49301eSmrg valid = EGL_TRUE; 3604a49301eSmrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 3614a49301eSmrg valid = EGL_TRUE; 3624a49301eSmrg } 363cdc920a0Smrg if (!valid) { 364cdc920a0Smrg _eglLog(_EGL_DEBUG, 365cdc920a0Smrg "attribute 0x%04x has an invalid value 0x%x", attr, val); 3664a49301eSmrg break; 367cdc920a0Smrg } 3684a49301eSmrg } 3694a49301eSmrg 3704a49301eSmrg /* any invalid attribute value should have been catched */ 3714a49301eSmrg if (!valid || for_matching) 3724a49301eSmrg return valid; 3734a49301eSmrg 3744a49301eSmrg /* now check for conflicting attribute values */ 3754a49301eSmrg 3763464ebd5Sriastradh switch (conf->ColorBufferType) { 3774a49301eSmrg case EGL_RGB_BUFFER: 3783464ebd5Sriastradh if (conf->LuminanceSize) 3794a49301eSmrg valid = EGL_FALSE; 3803464ebd5Sriastradh if (conf->RedSize + conf->GreenSize + 3813464ebd5Sriastradh conf->BlueSize + conf->AlphaSize != conf->BufferSize) 3824a49301eSmrg valid = EGL_FALSE; 3834a49301eSmrg break; 3844a49301eSmrg case EGL_LUMINANCE_BUFFER: 3853464ebd5Sriastradh if (conf->RedSize || conf->GreenSize || conf->BlueSize) 3864a49301eSmrg valid = EGL_FALSE; 3873464ebd5Sriastradh if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 3884a49301eSmrg valid = EGL_FALSE; 3894a49301eSmrg break; 3904a49301eSmrg } 391cdc920a0Smrg if (!valid) { 392cdc920a0Smrg _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 393cdc920a0Smrg return EGL_FALSE; 394cdc920a0Smrg } 3954a49301eSmrg 3963464ebd5Sriastradh if (!conf->SampleBuffers && conf->Samples) 3974a49301eSmrg valid = EGL_FALSE; 398cdc920a0Smrg if (!valid) { 399cdc920a0Smrg _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 400cdc920a0Smrg return EGL_FALSE; 401cdc920a0Smrg } 4024a49301eSmrg 4033464ebd5Sriastradh if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 4043464ebd5Sriastradh if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 4054a49301eSmrg valid = EGL_FALSE; 4064a49301eSmrg } 4073464ebd5Sriastradh if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 4083464ebd5Sriastradh if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 4094a49301eSmrg valid = EGL_FALSE; 4104a49301eSmrg } 411cdc920a0Smrg if (!valid) { 412cdc920a0Smrg _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 413cdc920a0Smrg return EGL_FALSE; 414cdc920a0Smrg } 4154a49301eSmrg 4164a49301eSmrg return valid; 4174a49301eSmrg} 4184a49301eSmrg 4194a49301eSmrg 4204a49301eSmrg/** 4214a49301eSmrg * Return true if a config matches the criteria. This and 4224a49301eSmrg * _eglParseConfigAttribList together implement the algorithm 4234a49301eSmrg * described in "Selection of EGLConfigs". 4244a49301eSmrg * 4254a49301eSmrg * Note that attributes that are special (currently, only 4264a49301eSmrg * EGL_MATCH_NATIVE_PIXMAP) are ignored. 4274a49301eSmrg */ 4284a49301eSmrgEGLBoolean 4294a49301eSmrg_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 4304a49301eSmrg{ 4314a49301eSmrg EGLint attr, val, i; 4324a49301eSmrg EGLBoolean matched = EGL_TRUE; 4334a49301eSmrg 4344a49301eSmrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 4354a49301eSmrg EGLint cmp; 4364a49301eSmrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 4374a49301eSmrg continue; 4384a49301eSmrg 4394a49301eSmrg attr = _eglValidationTable[i].attr; 4403464ebd5Sriastradh cmp = _eglGetConfigKey(criteria, attr); 4414a49301eSmrg if (cmp == EGL_DONT_CARE) 4424a49301eSmrg continue; 4434a49301eSmrg 4443464ebd5Sriastradh val = _eglGetConfigKey(conf, attr); 4454a49301eSmrg switch (_eglValidationTable[i].criterion) { 4464a49301eSmrg case ATTRIB_CRITERION_EXACT: 4474a49301eSmrg if (val != cmp) 4484a49301eSmrg matched = EGL_FALSE; 4494a49301eSmrg break; 4504a49301eSmrg case ATTRIB_CRITERION_ATLEAST: 4514a49301eSmrg if (val < cmp) 4524a49301eSmrg matched = EGL_FALSE; 4534a49301eSmrg break; 4544a49301eSmrg case ATTRIB_CRITERION_MASK: 4554a49301eSmrg if ((val & cmp) != cmp) 4564a49301eSmrg matched = EGL_FALSE; 4574a49301eSmrg break; 4584a49301eSmrg case ATTRIB_CRITERION_SPECIAL: 4594a49301eSmrg /* ignored here */ 4604a49301eSmrg break; 4614a49301eSmrg default: 4624a49301eSmrg assert(0); 4634a49301eSmrg break; 4644a49301eSmrg } 4654a49301eSmrg 466cdc920a0Smrg if (!matched) { 4673464ebd5Sriastradh#ifndef DEBUG 4683464ebd5Sriastradh /* only print the common errors when DEBUG is not defined */ 4693464ebd5Sriastradh if (attr != EGL_RENDERABLE_TYPE) 4703464ebd5Sriastradh break; 4713464ebd5Sriastradh#endif 472cdc920a0Smrg _eglLog(_EGL_DEBUG, 473cdc920a0Smrg "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 474cdc920a0Smrg val, attr, cmp); 4754a49301eSmrg break; 476cdc920a0Smrg } 4774a49301eSmrg } 4784a49301eSmrg 4794a49301eSmrg return matched; 4804a49301eSmrg} 4814a49301eSmrg 4823464ebd5Sriastradhstatic INLINE EGLBoolean 4833464ebd5Sriastradh_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 4843464ebd5Sriastradh{ 4853464ebd5Sriastradh if (_eglOffsetOfConfig(attr) < 0) 4863464ebd5Sriastradh return EGL_FALSE; 4873464ebd5Sriastradh 4883464ebd5Sriastradh switch (attr) { 4893464ebd5Sriastradh case EGL_Y_INVERTED_NOK: 4903464ebd5Sriastradh return conf->Display->Extensions.NOK_texture_from_pixmap; 4913464ebd5Sriastradh default: 4923464ebd5Sriastradh break; 4933464ebd5Sriastradh } 4943464ebd5Sriastradh 4953464ebd5Sriastradh return EGL_TRUE; 4963464ebd5Sriastradh} 4974a49301eSmrg 4984a49301eSmrg/** 4994a49301eSmrg * Initialize a criteria config from the given attribute list. 5004a49301eSmrg * Return EGL_FALSE if any of the attribute is invalid. 5014a49301eSmrg */ 5024a49301eSmrgEGLBoolean 5033464ebd5Sriastradh_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy, 5043464ebd5Sriastradh const EGLint *attrib_list) 5054a49301eSmrg{ 5064a49301eSmrg EGLint attr, val, i; 5073464ebd5Sriastradh 5083464ebd5Sriastradh _eglInitConfig(conf, dpy, EGL_DONT_CARE); 5094a49301eSmrg 5104a49301eSmrg /* reset to default values */ 5114a49301eSmrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 5124a49301eSmrg attr = _eglValidationTable[i].attr; 5134a49301eSmrg val = _eglValidationTable[i].default_value; 5143464ebd5Sriastradh _eglSetConfigKey(conf, attr, val); 5154a49301eSmrg } 5164a49301eSmrg 5174a49301eSmrg /* parse the list */ 5184a49301eSmrg for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 5194a49301eSmrg attr = attrib_list[i]; 5204a49301eSmrg val = attrib_list[i + 1]; 5214a49301eSmrg 5223464ebd5Sriastradh if (!_eglIsConfigAttribValid(conf, attr)) 5233464ebd5Sriastradh return EGL_FALSE; 5244a49301eSmrg 5253464ebd5Sriastradh _eglSetConfigKey(conf, attr, val); 5264a49301eSmrg } 5274a49301eSmrg 5284a49301eSmrg if (!_eglValidateConfig(conf, EGL_TRUE)) 5294a49301eSmrg return EGL_FALSE; 5304a49301eSmrg 5314a49301eSmrg /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ 5323464ebd5Sriastradh if (conf->Level == EGL_DONT_CARE) 5334a49301eSmrg return EGL_FALSE; 5344a49301eSmrg 5354a49301eSmrg /* ignore other attributes when EGL_CONFIG_ID is given */ 5363464ebd5Sriastradh if (conf->ConfigID != EGL_DONT_CARE) { 5373464ebd5Sriastradh for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 5383464ebd5Sriastradh attr = _eglValidationTable[i].attr; 5393464ebd5Sriastradh if (attr != EGL_CONFIG_ID) 5403464ebd5Sriastradh _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 5413464ebd5Sriastradh } 5424a49301eSmrg } 5434a49301eSmrg else { 5443464ebd5Sriastradh if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 5453464ebd5Sriastradh conf->NativeVisualType = EGL_DONT_CARE; 5464a49301eSmrg 5473464ebd5Sriastradh if (conf->TransparentType == EGL_NONE) { 5483464ebd5Sriastradh conf->TransparentRedValue = EGL_DONT_CARE; 5493464ebd5Sriastradh conf->TransparentGreenValue = EGL_DONT_CARE; 5503464ebd5Sriastradh conf->TransparentBlueValue = EGL_DONT_CARE; 5514a49301eSmrg } 5524a49301eSmrg } 5534a49301eSmrg 5544a49301eSmrg return EGL_TRUE; 5554a49301eSmrg} 5564a49301eSmrg 5574a49301eSmrg 5584a49301eSmrg/** 5594a49301eSmrg * Decide the ordering of conf1 and conf2, under the given criteria. 5604a49301eSmrg * When compare_id is true, this implements the algorithm described 5614a49301eSmrg * in "Sorting of EGLConfigs". When compare_id is false, 5624a49301eSmrg * EGL_CONFIG_ID is not compared. 5634a49301eSmrg * 5644a49301eSmrg * It returns a negative integer if conf1 is considered to come 5654a49301eSmrg * before conf2; a positive integer if conf2 is considered to come 5664a49301eSmrg * before conf1; zero if the ordering cannot be decided. 5674a49301eSmrg * 5684a49301eSmrg * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 5694a49301eSmrg * ignored here. 5704a49301eSmrg */ 5714a49301eSmrgEGLint 5724a49301eSmrg_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 5734a49301eSmrg const _EGLConfig *criteria, EGLBoolean compare_id) 5744a49301eSmrg{ 5754a49301eSmrg const EGLint compare_attribs[] = { 5764a49301eSmrg EGL_BUFFER_SIZE, 5774a49301eSmrg EGL_SAMPLE_BUFFERS, 5784a49301eSmrg EGL_SAMPLES, 5794a49301eSmrg EGL_DEPTH_SIZE, 5804a49301eSmrg EGL_STENCIL_SIZE, 5814a49301eSmrg EGL_ALPHA_MASK_SIZE, 5824a49301eSmrg }; 5834a49301eSmrg EGLint val1, val2; 5844a49301eSmrg EGLint i; 5854a49301eSmrg 5864a49301eSmrg if (conf1 == conf2) 5874a49301eSmrg return 0; 5884a49301eSmrg 5894a49301eSmrg /* the enum values have the desired ordering */ 5904a49301eSmrg assert(EGL_NONE < EGL_SLOW_CONFIG); 5914a49301eSmrg assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 5923464ebd5Sriastradh val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 5933464ebd5Sriastradh if (val1) 5943464ebd5Sriastradh return val1; 5954a49301eSmrg 5964a49301eSmrg /* the enum values have the desired ordering */ 5974a49301eSmrg assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 5983464ebd5Sriastradh val1 = conf1->ColorBufferType - conf2->ColorBufferType; 5993464ebd5Sriastradh if (val1) 6003464ebd5Sriastradh return val1; 6014a49301eSmrg 6024a49301eSmrg if (criteria) { 6034a49301eSmrg val1 = val2 = 0; 6043464ebd5Sriastradh if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 6053464ebd5Sriastradh if (criteria->RedSize > 0) { 6063464ebd5Sriastradh val1 += conf1->RedSize; 6073464ebd5Sriastradh val2 += conf2->RedSize; 6084a49301eSmrg } 6093464ebd5Sriastradh if (criteria->GreenSize > 0) { 6103464ebd5Sriastradh val1 += conf1->GreenSize; 6113464ebd5Sriastradh val2 += conf2->GreenSize; 6124a49301eSmrg } 6133464ebd5Sriastradh if (criteria->BlueSize > 0) { 6143464ebd5Sriastradh val1 += conf1->BlueSize; 6153464ebd5Sriastradh val2 += conf2->BlueSize; 6164a49301eSmrg } 6174a49301eSmrg } 6184a49301eSmrg else { 6193464ebd5Sriastradh if (criteria->LuminanceSize > 0) { 6203464ebd5Sriastradh val1 += conf1->LuminanceSize; 6213464ebd5Sriastradh val2 += conf2->LuminanceSize; 6224a49301eSmrg } 6234a49301eSmrg } 6243464ebd5Sriastradh if (criteria->AlphaSize > 0) { 6253464ebd5Sriastradh val1 += conf1->AlphaSize; 6263464ebd5Sriastradh val2 += conf2->AlphaSize; 6274a49301eSmrg } 6284a49301eSmrg } 6294a49301eSmrg else { 6304a49301eSmrg /* assume the default criteria, which gives no specific ordering */ 6314a49301eSmrg val1 = val2 = 0; 6324a49301eSmrg } 6334a49301eSmrg 6344a49301eSmrg /* for color bits, larger one is preferred */ 6354a49301eSmrg if (val1 != val2) 6364a49301eSmrg return (val2 - val1); 6374a49301eSmrg 6384a49301eSmrg for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 6393464ebd5Sriastradh val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 6403464ebd5Sriastradh val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 6414a49301eSmrg if (val1 != val2) 6424a49301eSmrg return (val1 - val2); 6434a49301eSmrg } 6444a49301eSmrg 6454a49301eSmrg /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 6464a49301eSmrg 6473464ebd5Sriastradh return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 6484a49301eSmrg} 6494a49301eSmrg 6504a49301eSmrg 6514a49301eSmrgstatic INLINE 6524a49301eSmrgvoid _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 6534a49301eSmrg{ 6544a49301eSmrg const _EGLConfig *tmp = *conf1; 6554a49301eSmrg *conf1 = *conf2; 6564a49301eSmrg *conf2 = tmp; 6574a49301eSmrg} 6584a49301eSmrg 6594a49301eSmrg 6604a49301eSmrg/** 6614a49301eSmrg * Quick sort an array of configs. This differs from the standard 6624a49301eSmrg * qsort() in that the compare function accepts an additional 6634a49301eSmrg * argument. 6644a49301eSmrg */ 6654a49301eSmrgvoid 6664a49301eSmrg_eglSortConfigs(const _EGLConfig **configs, EGLint count, 6674a49301eSmrg EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 6684a49301eSmrg void *), 6694a49301eSmrg void *priv_data) 6704a49301eSmrg{ 6714a49301eSmrg const EGLint pivot = 0; 6724a49301eSmrg EGLint i, j; 6734a49301eSmrg 6744a49301eSmrg if (count <= 1) 6754a49301eSmrg return; 6764a49301eSmrg 6774a49301eSmrg _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 6784a49301eSmrg i = 1; 6794a49301eSmrg j = count - 1; 6804a49301eSmrg do { 6814a49301eSmrg while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 6824a49301eSmrg i++; 6834a49301eSmrg while (compare(configs[j], configs[pivot], priv_data) > 0) 6844a49301eSmrg j--; 6854a49301eSmrg if (i < j) { 6864a49301eSmrg _eglSwapConfigs(&configs[i], &configs[j]); 6874a49301eSmrg i++; 6884a49301eSmrg j--; 6894a49301eSmrg } 6904a49301eSmrg else if (i == j) { 6914a49301eSmrg i++; 6924a49301eSmrg j--; 6934a49301eSmrg break; 6944a49301eSmrg } 6954a49301eSmrg } while (i <= j); 6964a49301eSmrg _eglSwapConfigs(&configs[pivot], &configs[j]); 6974a49301eSmrg 6984a49301eSmrg _eglSortConfigs(configs, j, compare, priv_data); 6994a49301eSmrg _eglSortConfigs(configs + i, count - i, compare, priv_data); 7004a49301eSmrg} 7014a49301eSmrg 7024a49301eSmrg 7034a49301eSmrgstatic int 7044a49301eSmrg_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, 7054a49301eSmrg void *priv_data) 7064a49301eSmrg{ 7074a49301eSmrg const _EGLConfig *criteria = (const _EGLConfig *) priv_data; 7084a49301eSmrg return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); 7094a49301eSmrg} 7104a49301eSmrg 7114a49301eSmrg 7124a49301eSmrg/** 7134a49301eSmrg * Typical fallback routine for eglChooseConfig 7144a49301eSmrg */ 7154a49301eSmrgEGLBoolean 7164a49301eSmrg_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, 7174a49301eSmrg EGLConfig *configs, EGLint config_size, EGLint *num_configs) 7184a49301eSmrg{ 7194a49301eSmrg _EGLConfig **configList, criteria; 7204a49301eSmrg EGLint i, count; 7214a49301eSmrg 7224a49301eSmrg if (!num_configs) 7234a49301eSmrg return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); 7244a49301eSmrg 7253464ebd5Sriastradh if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 7264a49301eSmrg return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 7274a49301eSmrg 7283464ebd5Sriastradh /* get the number of matched configs */ 7293464ebd5Sriastradh count = _eglFilterArray(disp->Configs, NULL, 0, 7303464ebd5Sriastradh (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria); 7313464ebd5Sriastradh if (!count) { 7323464ebd5Sriastradh *num_configs = count; 7333464ebd5Sriastradh return EGL_TRUE; 7343464ebd5Sriastradh } 7353464ebd5Sriastradh 7363464ebd5Sriastradh configList = malloc(sizeof(*configList) * count); 7374a49301eSmrg if (!configList) 7384a49301eSmrg return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 7394a49301eSmrg 7403464ebd5Sriastradh /* get the matched configs */ 7413464ebd5Sriastradh _eglFilterArray(disp->Configs, (void **) configList, count, 7423464ebd5Sriastradh (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria); 7434a49301eSmrg 7444a49301eSmrg /* perform sorting of configs */ 7454a49301eSmrg if (configs && count) { 7464a49301eSmrg _eglSortConfigs((const _EGLConfig **) configList, count, 7474a49301eSmrg _eglFallbackCompare, (void *) &criteria); 7484a49301eSmrg count = MIN2(count, config_size); 7494a49301eSmrg for (i = 0; i < count; i++) 7504a49301eSmrg configs[i] = _eglGetConfigHandle(configList[i]); 7514a49301eSmrg } 7524a49301eSmrg 7534a49301eSmrg free(configList); 7544a49301eSmrg 7554a49301eSmrg *num_configs = count; 7564a49301eSmrg 7574a49301eSmrg return EGL_TRUE; 7584a49301eSmrg} 7594a49301eSmrg 7604a49301eSmrg 7614a49301eSmrg/** 7624a49301eSmrg * Fallback for eglGetConfigAttrib. 7634a49301eSmrg */ 7644a49301eSmrgEGLBoolean 7654a49301eSmrg_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 7664a49301eSmrg EGLint attribute, EGLint *value) 7674a49301eSmrg{ 7684a49301eSmrg if (!_eglIsConfigAttribValid(conf, attribute)) 7694a49301eSmrg return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 7703464ebd5Sriastradh 7713464ebd5Sriastradh /* nonqueryable attributes */ 7723464ebd5Sriastradh switch (attribute) { 7733464ebd5Sriastradh case EGL_MATCH_NATIVE_PIXMAP: 7743464ebd5Sriastradh return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 7753464ebd5Sriastradh break; 7763464ebd5Sriastradh default: 7773464ebd5Sriastradh break; 7783464ebd5Sriastradh } 7793464ebd5Sriastradh 7804a49301eSmrg if (!value) 7814a49301eSmrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 7824a49301eSmrg 7833464ebd5Sriastradh *value = _eglGetConfigKey(conf, attribute); 7844a49301eSmrg return EGL_TRUE; 7854a49301eSmrg} 7864a49301eSmrg 7874a49301eSmrg 7883464ebd5Sriastradhstatic EGLBoolean 7893464ebd5Sriastradh_eglFlattenConfig(void *elem, void *buffer) 7903464ebd5Sriastradh{ 7913464ebd5Sriastradh _EGLConfig *conf = (_EGLConfig *) elem; 7923464ebd5Sriastradh EGLConfig *handle = (EGLConfig *) buffer; 7933464ebd5Sriastradh *handle = _eglGetConfigHandle(conf); 7943464ebd5Sriastradh return EGL_TRUE; 7953464ebd5Sriastradh} 7963464ebd5Sriastradh 7974a49301eSmrg/** 7984a49301eSmrg * Fallback for eglGetConfigs. 7994a49301eSmrg */ 8004a49301eSmrgEGLBoolean 8014a49301eSmrg_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, 8024a49301eSmrg EGLint config_size, EGLint *num_config) 8034a49301eSmrg{ 8044a49301eSmrg if (!num_config) 8054a49301eSmrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); 8064a49301eSmrg 8073464ebd5Sriastradh *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 8083464ebd5Sriastradh sizeof(configs[0]), config_size, _eglFlattenConfig); 8094a49301eSmrg 8104a49301eSmrg return EGL_TRUE; 8114a49301eSmrg} 812