eglconfig.c revision 848b8605
1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2008 VMware, Inc. 4848b8605Smrg * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 5848b8605Smrg * Copyright 2010-2011 LunarG, Inc. 6848b8605Smrg * All Rights Reserved. 7848b8605Smrg * 8848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9848b8605Smrg * copy of this software and associated documentation files (the 10848b8605Smrg * "Software"), to deal in the Software without restriction, including 11848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 12848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 13848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 14848b8605Smrg * the following conditions: 15848b8605Smrg * 16848b8605Smrg * The above copyright notice and this permission notice (including the 17848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 18848b8605Smrg * of the Software. 19848b8605Smrg * 20848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26848b8605Smrg * DEALINGS IN THE SOFTWARE. 27848b8605Smrg * 28848b8605Smrg **************************************************************************/ 29848b8605Smrg 30848b8605Smrg 31848b8605Smrg/** 32848b8605Smrg * EGL Configuration (pixel format) functions. 33848b8605Smrg */ 34848b8605Smrg 35848b8605Smrg 36848b8605Smrg#include <stdlib.h> 37848b8605Smrg#include <string.h> 38848b8605Smrg#include <assert.h> 39848b8605Smrg#include "eglconfig.h" 40848b8605Smrg#include "egldisplay.h" 41848b8605Smrg#include "eglcurrent.h" 42848b8605Smrg#include "egllog.h" 43848b8605Smrg 44848b8605Smrg 45848b8605Smrg#define MIN2(A, B) (((A) < (B)) ? (A) : (B)) 46848b8605Smrg 47848b8605Smrg 48848b8605Smrg/** 49848b8605Smrg * Init the given _EGLconfig to default values. 50848b8605Smrg * \param id the configuration's ID. 51848b8605Smrg * 52848b8605Smrg * Note that id must be positive for the config to be valid. 53848b8605Smrg * It is also recommended that when there are N configs, their 54848b8605Smrg * IDs are from 1 to N respectively. 55848b8605Smrg */ 56848b8605Smrgvoid 57848b8605Smrg_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id) 58848b8605Smrg{ 59848b8605Smrg memset(conf, 0, sizeof(*conf)); 60848b8605Smrg 61848b8605Smrg conf->Display = dpy; 62848b8605Smrg 63848b8605Smrg /* some attributes take non-zero default values */ 64848b8605Smrg conf->ConfigID = id; 65848b8605Smrg conf->ConfigCaveat = EGL_NONE; 66848b8605Smrg conf->TransparentType = EGL_NONE; 67848b8605Smrg conf->NativeVisualType = EGL_NONE; 68848b8605Smrg conf->ColorBufferType = EGL_RGB_BUFFER; 69848b8605Smrg} 70848b8605Smrg 71848b8605Smrg 72848b8605Smrg/** 73848b8605Smrg * Link a config to its display and return the handle of the link. 74848b8605Smrg * The handle can be passed to client directly. 75848b8605Smrg * 76848b8605Smrg * Note that we just save the ptr to the config (we don't copy the config). 77848b8605Smrg */ 78848b8605SmrgPUBLIC EGLConfig 79848b8605Smrg_eglLinkConfig(_EGLConfig *conf) 80848b8605Smrg{ 81848b8605Smrg _EGLDisplay *dpy = conf->Display; 82848b8605Smrg 83848b8605Smrg /* sanity check */ 84848b8605Smrg assert(dpy && conf->ConfigID > 0); 85848b8605Smrg 86848b8605Smrg if (!dpy->Configs) { 87848b8605Smrg dpy->Configs = _eglCreateArray("Config", 16); 88848b8605Smrg if (!dpy->Configs) 89848b8605Smrg return (EGLConfig) NULL; 90848b8605Smrg } 91848b8605Smrg 92848b8605Smrg _eglAppendArray(dpy->Configs, (void *) conf); 93848b8605Smrg 94848b8605Smrg return (EGLConfig) conf; 95848b8605Smrg} 96848b8605Smrg 97848b8605Smrg 98848b8605Smrg/** 99848b8605Smrg * Lookup a handle to find the linked config. 100848b8605Smrg * Return NULL if the handle has no corresponding linked config. 101848b8605Smrg */ 102848b8605Smrg_EGLConfig * 103848b8605Smrg_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy) 104848b8605Smrg{ 105848b8605Smrg _EGLConfig *conf; 106848b8605Smrg 107848b8605Smrg if (!dpy) 108848b8605Smrg return NULL; 109848b8605Smrg 110848b8605Smrg conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config); 111848b8605Smrg if (conf) 112848b8605Smrg assert(conf->Display == dpy); 113848b8605Smrg 114848b8605Smrg return conf; 115848b8605Smrg} 116848b8605Smrg 117848b8605Smrg 118848b8605Smrgenum { 119848b8605Smrg /* types */ 120848b8605Smrg ATTRIB_TYPE_INTEGER, 121848b8605Smrg ATTRIB_TYPE_BOOLEAN, 122848b8605Smrg ATTRIB_TYPE_BITMASK, 123848b8605Smrg ATTRIB_TYPE_ENUM, 124848b8605Smrg ATTRIB_TYPE_PSEUDO, /* non-queryable */ 125848b8605Smrg ATTRIB_TYPE_PLATFORM, /* platform-dependent */ 126848b8605Smrg /* criteria */ 127848b8605Smrg ATTRIB_CRITERION_EXACT, 128848b8605Smrg ATTRIB_CRITERION_ATLEAST, 129848b8605Smrg ATTRIB_CRITERION_MASK, 130848b8605Smrg ATTRIB_CRITERION_SPECIAL, 131848b8605Smrg ATTRIB_CRITERION_IGNORE 132848b8605Smrg}; 133848b8605Smrg 134848b8605Smrg 135848b8605Smrg/* EGL spec Table 3.1 and 3.4 */ 136848b8605Smrgstatic const struct { 137848b8605Smrg EGLint attr; 138848b8605Smrg EGLint type; 139848b8605Smrg EGLint criterion; 140848b8605Smrg EGLint default_value; 141848b8605Smrg} _eglValidationTable[] = 142848b8605Smrg{ 143848b8605Smrg /* core */ 144848b8605Smrg { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, 145848b8605Smrg ATTRIB_CRITERION_ATLEAST, 146848b8605Smrg 0 }, 147848b8605Smrg { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, 148848b8605Smrg ATTRIB_CRITERION_ATLEAST, 149848b8605Smrg 0 }, 150848b8605Smrg { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, 151848b8605Smrg ATTRIB_CRITERION_ATLEAST, 152848b8605Smrg 0 }, 153848b8605Smrg { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, 154848b8605Smrg ATTRIB_CRITERION_ATLEAST, 155848b8605Smrg 0 }, 156848b8605Smrg { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, 157848b8605Smrg ATTRIB_CRITERION_ATLEAST, 158848b8605Smrg 0 }, 159848b8605Smrg { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, 160848b8605Smrg ATTRIB_CRITERION_ATLEAST, 161848b8605Smrg 0 }, 162848b8605Smrg { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, 163848b8605Smrg ATTRIB_CRITERION_ATLEAST, 164848b8605Smrg 0 }, 165848b8605Smrg { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, 166848b8605Smrg ATTRIB_CRITERION_EXACT, 167848b8605Smrg EGL_DONT_CARE }, 168848b8605Smrg { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, 169848b8605Smrg ATTRIB_CRITERION_EXACT, 170848b8605Smrg EGL_DONT_CARE }, 171848b8605Smrg { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, 172848b8605Smrg ATTRIB_CRITERION_EXACT, 173848b8605Smrg EGL_RGB_BUFFER }, 174848b8605Smrg { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, 175848b8605Smrg ATTRIB_CRITERION_EXACT, 176848b8605Smrg EGL_DONT_CARE }, 177848b8605Smrg { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, 178848b8605Smrg ATTRIB_CRITERION_EXACT, 179848b8605Smrg EGL_DONT_CARE }, 180848b8605Smrg { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, 181848b8605Smrg ATTRIB_CRITERION_MASK, 182848b8605Smrg 0 }, 183848b8605Smrg { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, 184848b8605Smrg ATTRIB_CRITERION_ATLEAST, 185848b8605Smrg 0 }, 186848b8605Smrg { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, 187848b8605Smrg ATTRIB_CRITERION_EXACT, 188848b8605Smrg 0 }, 189848b8605Smrg { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, 190848b8605Smrg ATTRIB_CRITERION_IGNORE, 191848b8605Smrg 0 }, 192848b8605Smrg { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, 193848b8605Smrg ATTRIB_CRITERION_IGNORE, 194848b8605Smrg 0 }, 195848b8605Smrg { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, 196848b8605Smrg ATTRIB_CRITERION_IGNORE, 197848b8605Smrg 0 }, 198848b8605Smrg { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 199848b8605Smrg ATTRIB_CRITERION_EXACT, 200848b8605Smrg EGL_DONT_CARE }, 201848b8605Smrg { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 202848b8605Smrg ATTRIB_CRITERION_EXACT, 203848b8605Smrg EGL_DONT_CARE }, 204848b8605Smrg { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, 205848b8605Smrg ATTRIB_CRITERION_EXACT, 206848b8605Smrg EGL_DONT_CARE }, 207848b8605Smrg { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, 208848b8605Smrg ATTRIB_CRITERION_IGNORE, 209848b8605Smrg 0 }, 210848b8605Smrg { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, 211848b8605Smrg ATTRIB_CRITERION_EXACT, 212848b8605Smrg EGL_DONT_CARE }, 213848b8605Smrg { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, 214848b8605Smrg ATTRIB_CRITERION_MASK, 215848b8605Smrg EGL_OPENGL_ES_BIT }, 216848b8605Smrg { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, 217848b8605Smrg ATTRIB_CRITERION_ATLEAST, 218848b8605Smrg 0 }, 219848b8605Smrg { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, 220848b8605Smrg ATTRIB_CRITERION_ATLEAST, 221848b8605Smrg 0 }, 222848b8605Smrg { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, 223848b8605Smrg ATTRIB_CRITERION_ATLEAST, 224848b8605Smrg 0 }, 225848b8605Smrg { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, 226848b8605Smrg ATTRIB_CRITERION_MASK, 227848b8605Smrg EGL_WINDOW_BIT }, 228848b8605Smrg { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, 229848b8605Smrg ATTRIB_CRITERION_EXACT, 230848b8605Smrg EGL_NONE }, 231848b8605Smrg { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, 232848b8605Smrg ATTRIB_CRITERION_EXACT, 233848b8605Smrg EGL_DONT_CARE }, 234848b8605Smrg { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, 235848b8605Smrg ATTRIB_CRITERION_EXACT, 236848b8605Smrg EGL_DONT_CARE }, 237848b8605Smrg { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, 238848b8605Smrg ATTRIB_CRITERION_EXACT, 239848b8605Smrg EGL_DONT_CARE }, 240848b8605Smrg { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, 241848b8605Smrg ATTRIB_CRITERION_SPECIAL, 242848b8605Smrg EGL_NONE }, 243848b8605Smrg /* extensions */ 244848b8605Smrg { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, 245848b8605Smrg ATTRIB_CRITERION_EXACT, 246848b8605Smrg EGL_DONT_CARE } 247848b8605Smrg}; 248848b8605Smrg 249848b8605Smrg 250848b8605Smrg/** 251848b8605Smrg * Return true if a config is valid. When for_matching is true, 252848b8605Smrg * EGL_DONT_CARE is accepted as a valid attribute value, and checks 253848b8605Smrg * for conflicting attribute values are skipped. 254848b8605Smrg * 255848b8605Smrg * Note that some attributes are platform-dependent and are not 256848b8605Smrg * checked. 257848b8605Smrg */ 258848b8605SmrgEGLBoolean 259848b8605Smrg_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) 260848b8605Smrg{ 261848b8605Smrg EGLint i, attr, val; 262848b8605Smrg EGLBoolean valid = EGL_TRUE; 263848b8605Smrg 264848b8605Smrg /* check attributes by their types */ 265848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 266848b8605Smrg EGLint mask; 267848b8605Smrg 268848b8605Smrg attr = _eglValidationTable[i].attr; 269848b8605Smrg val = _eglGetConfigKey(conf, attr); 270848b8605Smrg 271848b8605Smrg switch (_eglValidationTable[i].type) { 272848b8605Smrg case ATTRIB_TYPE_INTEGER: 273848b8605Smrg switch (attr) { 274848b8605Smrg case EGL_CONFIG_ID: 275848b8605Smrg /* config id must be positive */ 276848b8605Smrg if (val <= 0) 277848b8605Smrg valid = EGL_FALSE; 278848b8605Smrg break; 279848b8605Smrg case EGL_SAMPLE_BUFFERS: 280848b8605Smrg /* there can be at most 1 sample buffer */ 281848b8605Smrg if (val > 1 || val < 0) 282848b8605Smrg valid = EGL_FALSE; 283848b8605Smrg break; 284848b8605Smrg default: 285848b8605Smrg if (val < 0) 286848b8605Smrg valid = EGL_FALSE; 287848b8605Smrg break; 288848b8605Smrg } 289848b8605Smrg break; 290848b8605Smrg case ATTRIB_TYPE_BOOLEAN: 291848b8605Smrg if (val != EGL_TRUE && val != EGL_FALSE) 292848b8605Smrg valid = EGL_FALSE; 293848b8605Smrg break; 294848b8605Smrg case ATTRIB_TYPE_ENUM: 295848b8605Smrg switch (attr) { 296848b8605Smrg case EGL_CONFIG_CAVEAT: 297848b8605Smrg if (val != EGL_NONE && val != EGL_SLOW_CONFIG && 298848b8605Smrg val != EGL_NON_CONFORMANT_CONFIG) 299848b8605Smrg valid = EGL_FALSE; 300848b8605Smrg break; 301848b8605Smrg case EGL_TRANSPARENT_TYPE: 302848b8605Smrg if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) 303848b8605Smrg valid = EGL_FALSE; 304848b8605Smrg break; 305848b8605Smrg case EGL_COLOR_BUFFER_TYPE: 306848b8605Smrg if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) 307848b8605Smrg valid = EGL_FALSE; 308848b8605Smrg break; 309848b8605Smrg default: 310848b8605Smrg assert(0); 311848b8605Smrg break; 312848b8605Smrg } 313848b8605Smrg break; 314848b8605Smrg case ATTRIB_TYPE_BITMASK: 315848b8605Smrg switch (attr) { 316848b8605Smrg case EGL_SURFACE_TYPE: 317848b8605Smrg mask = EGL_PBUFFER_BIT | 318848b8605Smrg EGL_PIXMAP_BIT | 319848b8605Smrg EGL_WINDOW_BIT | 320848b8605Smrg EGL_VG_COLORSPACE_LINEAR_BIT | 321848b8605Smrg EGL_VG_ALPHA_FORMAT_PRE_BIT | 322848b8605Smrg EGL_MULTISAMPLE_RESOLVE_BOX_BIT | 323848b8605Smrg EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 324848b8605Smrg#ifdef EGL_MESA_screen_surface 325848b8605Smrg if (conf->Display->Extensions.MESA_screen_surface) 326848b8605Smrg mask |= EGL_SCREEN_BIT_MESA; 327848b8605Smrg#endif 328848b8605Smrg break; 329848b8605Smrg case EGL_RENDERABLE_TYPE: 330848b8605Smrg case EGL_CONFORMANT: 331848b8605Smrg mask = EGL_OPENGL_ES_BIT | 332848b8605Smrg EGL_OPENVG_BIT | 333848b8605Smrg EGL_OPENGL_ES2_BIT | 334848b8605Smrg EGL_OPENGL_ES3_BIT_KHR | 335848b8605Smrg EGL_OPENGL_BIT; 336848b8605Smrg break; 337848b8605Smrg default: 338848b8605Smrg assert(0); 339848b8605Smrg mask = 0; 340848b8605Smrg break; 341848b8605Smrg } 342848b8605Smrg if (val & ~mask) 343848b8605Smrg valid = EGL_FALSE; 344848b8605Smrg break; 345848b8605Smrg case ATTRIB_TYPE_PLATFORM: 346848b8605Smrg /* unable to check platform-dependent attributes here */ 347848b8605Smrg break; 348848b8605Smrg case ATTRIB_TYPE_PSEUDO: 349848b8605Smrg /* pseudo attributes should not be set */ 350848b8605Smrg if (val != 0) 351848b8605Smrg valid = EGL_FALSE; 352848b8605Smrg break; 353848b8605Smrg default: 354848b8605Smrg assert(0); 355848b8605Smrg break; 356848b8605Smrg } 357848b8605Smrg 358848b8605Smrg if (!valid && for_matching) { 359848b8605Smrg /* accept EGL_DONT_CARE as a valid value */ 360848b8605Smrg if (val == EGL_DONT_CARE) 361848b8605Smrg valid = EGL_TRUE; 362848b8605Smrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 363848b8605Smrg valid = EGL_TRUE; 364848b8605Smrg } 365848b8605Smrg if (!valid) { 366848b8605Smrg _eglLog(_EGL_DEBUG, 367848b8605Smrg "attribute 0x%04x has an invalid value 0x%x", attr, val); 368848b8605Smrg break; 369848b8605Smrg } 370848b8605Smrg } 371848b8605Smrg 372848b8605Smrg /* any invalid attribute value should have been catched */ 373848b8605Smrg if (!valid || for_matching) 374848b8605Smrg return valid; 375848b8605Smrg 376848b8605Smrg /* now check for conflicting attribute values */ 377848b8605Smrg 378848b8605Smrg switch (conf->ColorBufferType) { 379848b8605Smrg case EGL_RGB_BUFFER: 380848b8605Smrg if (conf->LuminanceSize) 381848b8605Smrg valid = EGL_FALSE; 382848b8605Smrg if (conf->RedSize + conf->GreenSize + 383848b8605Smrg conf->BlueSize + conf->AlphaSize != conf->BufferSize) 384848b8605Smrg valid = EGL_FALSE; 385848b8605Smrg break; 386848b8605Smrg case EGL_LUMINANCE_BUFFER: 387848b8605Smrg if (conf->RedSize || conf->GreenSize || conf->BlueSize) 388848b8605Smrg valid = EGL_FALSE; 389848b8605Smrg if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 390848b8605Smrg valid = EGL_FALSE; 391848b8605Smrg break; 392848b8605Smrg } 393848b8605Smrg if (!valid) { 394848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 395848b8605Smrg return EGL_FALSE; 396848b8605Smrg } 397848b8605Smrg 398848b8605Smrg if (!conf->SampleBuffers && conf->Samples) 399848b8605Smrg valid = EGL_FALSE; 400848b8605Smrg if (!valid) { 401848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 402848b8605Smrg return EGL_FALSE; 403848b8605Smrg } 404848b8605Smrg 405848b8605Smrg if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 406848b8605Smrg if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 407848b8605Smrg valid = EGL_FALSE; 408848b8605Smrg } 409848b8605Smrg if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 410848b8605Smrg if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 411848b8605Smrg valid = EGL_FALSE; 412848b8605Smrg } 413848b8605Smrg if (!valid) { 414848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 415848b8605Smrg return EGL_FALSE; 416848b8605Smrg } 417848b8605Smrg 418848b8605Smrg return valid; 419848b8605Smrg} 420848b8605Smrg 421848b8605Smrg 422848b8605Smrg/** 423848b8605Smrg * Return true if a config matches the criteria. This and 424848b8605Smrg * _eglParseConfigAttribList together implement the algorithm 425848b8605Smrg * described in "Selection of EGLConfigs". 426848b8605Smrg * 427848b8605Smrg * Note that attributes that are special (currently, only 428848b8605Smrg * EGL_MATCH_NATIVE_PIXMAP) are ignored. 429848b8605Smrg */ 430848b8605SmrgEGLBoolean 431848b8605Smrg_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 432848b8605Smrg{ 433848b8605Smrg EGLint attr, val, i; 434848b8605Smrg EGLBoolean matched = EGL_TRUE; 435848b8605Smrg 436848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 437848b8605Smrg EGLint cmp; 438848b8605Smrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 439848b8605Smrg continue; 440848b8605Smrg 441848b8605Smrg attr = _eglValidationTable[i].attr; 442848b8605Smrg cmp = _eglGetConfigKey(criteria, attr); 443848b8605Smrg if (cmp == EGL_DONT_CARE) 444848b8605Smrg continue; 445848b8605Smrg 446848b8605Smrg val = _eglGetConfigKey(conf, attr); 447848b8605Smrg switch (_eglValidationTable[i].criterion) { 448848b8605Smrg case ATTRIB_CRITERION_EXACT: 449848b8605Smrg if (val != cmp) 450848b8605Smrg matched = EGL_FALSE; 451848b8605Smrg break; 452848b8605Smrg case ATTRIB_CRITERION_ATLEAST: 453848b8605Smrg if (val < cmp) 454848b8605Smrg matched = EGL_FALSE; 455848b8605Smrg break; 456848b8605Smrg case ATTRIB_CRITERION_MASK: 457848b8605Smrg if ((val & cmp) != cmp) 458848b8605Smrg matched = EGL_FALSE; 459848b8605Smrg break; 460848b8605Smrg case ATTRIB_CRITERION_SPECIAL: 461848b8605Smrg /* ignored here */ 462848b8605Smrg break; 463848b8605Smrg default: 464848b8605Smrg assert(0); 465848b8605Smrg break; 466848b8605Smrg } 467848b8605Smrg 468848b8605Smrg if (!matched) { 469848b8605Smrg#ifndef DEBUG 470848b8605Smrg /* only print the common errors when DEBUG is not defined */ 471848b8605Smrg if (attr != EGL_RENDERABLE_TYPE) 472848b8605Smrg break; 473848b8605Smrg#endif 474848b8605Smrg _eglLog(_EGL_DEBUG, 475848b8605Smrg "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 476848b8605Smrg val, attr, cmp); 477848b8605Smrg break; 478848b8605Smrg } 479848b8605Smrg } 480848b8605Smrg 481848b8605Smrg return matched; 482848b8605Smrg} 483848b8605Smrg 484848b8605Smrgstatic INLINE EGLBoolean 485848b8605Smrg_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 486848b8605Smrg{ 487848b8605Smrg if (_eglOffsetOfConfig(attr) < 0) 488848b8605Smrg return EGL_FALSE; 489848b8605Smrg 490848b8605Smrg switch (attr) { 491848b8605Smrg case EGL_Y_INVERTED_NOK: 492848b8605Smrg return conf->Display->Extensions.NOK_texture_from_pixmap; 493848b8605Smrg default: 494848b8605Smrg break; 495848b8605Smrg } 496848b8605Smrg 497848b8605Smrg return EGL_TRUE; 498848b8605Smrg} 499848b8605Smrg 500848b8605Smrg/** 501848b8605Smrg * Initialize a criteria config from the given attribute list. 502848b8605Smrg * Return EGL_FALSE if any of the attribute is invalid. 503848b8605Smrg */ 504848b8605SmrgEGLBoolean 505848b8605Smrg_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy, 506848b8605Smrg const EGLint *attrib_list) 507848b8605Smrg{ 508848b8605Smrg EGLint attr, val, i; 509848b8605Smrg 510848b8605Smrg _eglInitConfig(conf, dpy, EGL_DONT_CARE); 511848b8605Smrg 512848b8605Smrg /* reset to default values */ 513848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 514848b8605Smrg attr = _eglValidationTable[i].attr; 515848b8605Smrg val = _eglValidationTable[i].default_value; 516848b8605Smrg _eglSetConfigKey(conf, attr, val); 517848b8605Smrg } 518848b8605Smrg 519848b8605Smrg /* parse the list */ 520848b8605Smrg for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 521848b8605Smrg attr = attrib_list[i]; 522848b8605Smrg val = attrib_list[i + 1]; 523848b8605Smrg 524848b8605Smrg if (!_eglIsConfigAttribValid(conf, attr)) 525848b8605Smrg return EGL_FALSE; 526848b8605Smrg 527848b8605Smrg _eglSetConfigKey(conf, attr, val); 528848b8605Smrg } 529848b8605Smrg 530848b8605Smrg if (!_eglValidateConfig(conf, EGL_TRUE)) 531848b8605Smrg return EGL_FALSE; 532848b8605Smrg 533848b8605Smrg /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */ 534848b8605Smrg if (conf->Level == EGL_DONT_CARE || 535848b8605Smrg conf->MatchNativePixmap == EGL_DONT_CARE) 536848b8605Smrg return EGL_FALSE; 537848b8605Smrg 538848b8605Smrg /* ignore other attributes when EGL_CONFIG_ID is given */ 539848b8605Smrg if (conf->ConfigID != EGL_DONT_CARE) { 540848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 541848b8605Smrg attr = _eglValidationTable[i].attr; 542848b8605Smrg if (attr != EGL_CONFIG_ID) 543848b8605Smrg _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 544848b8605Smrg } 545848b8605Smrg } 546848b8605Smrg else { 547848b8605Smrg if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 548848b8605Smrg conf->NativeVisualType = EGL_DONT_CARE; 549848b8605Smrg 550848b8605Smrg if (conf->TransparentType == EGL_NONE) { 551848b8605Smrg conf->TransparentRedValue = EGL_DONT_CARE; 552848b8605Smrg conf->TransparentGreenValue = EGL_DONT_CARE; 553848b8605Smrg conf->TransparentBlueValue = EGL_DONT_CARE; 554848b8605Smrg } 555848b8605Smrg } 556848b8605Smrg 557848b8605Smrg return EGL_TRUE; 558848b8605Smrg} 559848b8605Smrg 560848b8605Smrg 561848b8605Smrg/** 562848b8605Smrg * Decide the ordering of conf1 and conf2, under the given criteria. 563848b8605Smrg * When compare_id is true, this implements the algorithm described 564848b8605Smrg * in "Sorting of EGLConfigs". When compare_id is false, 565848b8605Smrg * EGL_CONFIG_ID is not compared. 566848b8605Smrg * 567848b8605Smrg * It returns a negative integer if conf1 is considered to come 568848b8605Smrg * before conf2; a positive integer if conf2 is considered to come 569848b8605Smrg * before conf1; zero if the ordering cannot be decided. 570848b8605Smrg * 571848b8605Smrg * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 572848b8605Smrg * ignored here. 573848b8605Smrg */ 574848b8605SmrgEGLint 575848b8605Smrg_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 576848b8605Smrg const _EGLConfig *criteria, EGLBoolean compare_id) 577848b8605Smrg{ 578848b8605Smrg const EGLint compare_attribs[] = { 579848b8605Smrg EGL_BUFFER_SIZE, 580848b8605Smrg EGL_SAMPLE_BUFFERS, 581848b8605Smrg EGL_SAMPLES, 582848b8605Smrg EGL_DEPTH_SIZE, 583848b8605Smrg EGL_STENCIL_SIZE, 584848b8605Smrg EGL_ALPHA_MASK_SIZE, 585848b8605Smrg }; 586848b8605Smrg EGLint val1, val2; 587848b8605Smrg EGLint i; 588848b8605Smrg 589848b8605Smrg if (conf1 == conf2) 590848b8605Smrg return 0; 591848b8605Smrg 592848b8605Smrg /* the enum values have the desired ordering */ 593848b8605Smrg assert(EGL_NONE < EGL_SLOW_CONFIG); 594848b8605Smrg assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 595848b8605Smrg val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 596848b8605Smrg if (val1) 597848b8605Smrg return val1; 598848b8605Smrg 599848b8605Smrg /* the enum values have the desired ordering */ 600848b8605Smrg assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 601848b8605Smrg val1 = conf1->ColorBufferType - conf2->ColorBufferType; 602848b8605Smrg if (val1) 603848b8605Smrg return val1; 604848b8605Smrg 605848b8605Smrg if (criteria) { 606848b8605Smrg val1 = val2 = 0; 607848b8605Smrg if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 608848b8605Smrg if (criteria->RedSize > 0) { 609848b8605Smrg val1 += conf1->RedSize; 610848b8605Smrg val2 += conf2->RedSize; 611848b8605Smrg } 612848b8605Smrg if (criteria->GreenSize > 0) { 613848b8605Smrg val1 += conf1->GreenSize; 614848b8605Smrg val2 += conf2->GreenSize; 615848b8605Smrg } 616848b8605Smrg if (criteria->BlueSize > 0) { 617848b8605Smrg val1 += conf1->BlueSize; 618848b8605Smrg val2 += conf2->BlueSize; 619848b8605Smrg } 620848b8605Smrg } 621848b8605Smrg else { 622848b8605Smrg if (criteria->LuminanceSize > 0) { 623848b8605Smrg val1 += conf1->LuminanceSize; 624848b8605Smrg val2 += conf2->LuminanceSize; 625848b8605Smrg } 626848b8605Smrg } 627848b8605Smrg if (criteria->AlphaSize > 0) { 628848b8605Smrg val1 += conf1->AlphaSize; 629848b8605Smrg val2 += conf2->AlphaSize; 630848b8605Smrg } 631848b8605Smrg } 632848b8605Smrg else { 633848b8605Smrg /* assume the default criteria, which gives no specific ordering */ 634848b8605Smrg val1 = val2 = 0; 635848b8605Smrg } 636848b8605Smrg 637848b8605Smrg /* for color bits, larger one is preferred */ 638848b8605Smrg if (val1 != val2) 639848b8605Smrg return (val2 - val1); 640848b8605Smrg 641848b8605Smrg for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 642848b8605Smrg val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 643848b8605Smrg val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 644848b8605Smrg if (val1 != val2) 645848b8605Smrg return (val1 - val2); 646848b8605Smrg } 647848b8605Smrg 648848b8605Smrg /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 649848b8605Smrg 650848b8605Smrg return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 651848b8605Smrg} 652848b8605Smrg 653848b8605Smrg 654848b8605Smrgstatic INLINE 655848b8605Smrgvoid _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 656848b8605Smrg{ 657848b8605Smrg const _EGLConfig *tmp = *conf1; 658848b8605Smrg *conf1 = *conf2; 659848b8605Smrg *conf2 = tmp; 660848b8605Smrg} 661848b8605Smrg 662848b8605Smrg 663848b8605Smrg/** 664848b8605Smrg * Quick sort an array of configs. This differs from the standard 665848b8605Smrg * qsort() in that the compare function accepts an additional 666848b8605Smrg * argument. 667848b8605Smrg */ 668848b8605Smrgstatic void 669848b8605Smrg_eglSortConfigs(const _EGLConfig **configs, EGLint count, 670848b8605Smrg EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 671848b8605Smrg void *), 672848b8605Smrg void *priv_data) 673848b8605Smrg{ 674848b8605Smrg const EGLint pivot = 0; 675848b8605Smrg EGLint i, j; 676848b8605Smrg 677848b8605Smrg if (count <= 1) 678848b8605Smrg return; 679848b8605Smrg 680848b8605Smrg _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 681848b8605Smrg i = 1; 682848b8605Smrg j = count - 1; 683848b8605Smrg do { 684848b8605Smrg while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 685848b8605Smrg i++; 686848b8605Smrg while (compare(configs[j], configs[pivot], priv_data) > 0) 687848b8605Smrg j--; 688848b8605Smrg if (i < j) { 689848b8605Smrg _eglSwapConfigs(&configs[i], &configs[j]); 690848b8605Smrg i++; 691848b8605Smrg j--; 692848b8605Smrg } 693848b8605Smrg else if (i == j) { 694848b8605Smrg i++; 695848b8605Smrg j--; 696848b8605Smrg break; 697848b8605Smrg } 698848b8605Smrg } while (i <= j); 699848b8605Smrg _eglSwapConfigs(&configs[pivot], &configs[j]); 700848b8605Smrg 701848b8605Smrg _eglSortConfigs(configs, j, compare, priv_data); 702848b8605Smrg _eglSortConfigs(configs + i, count - i, compare, priv_data); 703848b8605Smrg} 704848b8605Smrg 705848b8605Smrg 706848b8605Smrg/** 707848b8605Smrg * A helper function for implementing eglChooseConfig. See _eglFilterArray and 708848b8605Smrg * _eglSortConfigs for the meanings of match and compare. 709848b8605Smrg */ 710848b8605SmrgEGLBoolean 711848b8605Smrg_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, 712848b8605Smrg EGLint config_size, EGLint *num_configs, 713848b8605Smrg EGLBoolean (*match)(const _EGLConfig *, void *), 714848b8605Smrg EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 715848b8605Smrg void *), 716848b8605Smrg void *priv_data) 717848b8605Smrg{ 718848b8605Smrg _EGLConfig **configList; 719848b8605Smrg EGLint i, count; 720848b8605Smrg 721848b8605Smrg if (!num_configs) 722848b8605Smrg return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); 723848b8605Smrg 724848b8605Smrg /* get the number of matched configs */ 725848b8605Smrg count = _eglFilterArray(array, NULL, 0, 726848b8605Smrg (_EGLArrayForEach) match, priv_data); 727848b8605Smrg if (!count) { 728848b8605Smrg *num_configs = count; 729848b8605Smrg return EGL_TRUE; 730848b8605Smrg } 731848b8605Smrg 732848b8605Smrg configList = malloc(sizeof(*configList) * count); 733848b8605Smrg if (!configList) 734848b8605Smrg return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 735848b8605Smrg 736848b8605Smrg /* get the matched configs */ 737848b8605Smrg _eglFilterArray(array, (void **) configList, count, 738848b8605Smrg (_EGLArrayForEach) match, priv_data); 739848b8605Smrg 740848b8605Smrg /* perform sorting of configs */ 741848b8605Smrg if (configs && count) { 742848b8605Smrg _eglSortConfigs((const _EGLConfig **) configList, count, 743848b8605Smrg compare, priv_data); 744848b8605Smrg count = MIN2(count, config_size); 745848b8605Smrg for (i = 0; i < count; i++) 746848b8605Smrg configs[i] = _eglGetConfigHandle(configList[i]); 747848b8605Smrg } 748848b8605Smrg 749848b8605Smrg free(configList); 750848b8605Smrg 751848b8605Smrg *num_configs = count; 752848b8605Smrg 753848b8605Smrg return EGL_TRUE; 754848b8605Smrg} 755848b8605Smrg 756848b8605Smrg 757848b8605Smrgstatic EGLBoolean 758848b8605Smrg_eglFallbackMatch(const _EGLConfig *conf, void *priv_data) 759848b8605Smrg{ 760848b8605Smrg return _eglMatchConfig(conf, (const _EGLConfig *) priv_data); 761848b8605Smrg} 762848b8605Smrg 763848b8605Smrg 764848b8605Smrgstatic EGLint 765848b8605Smrg_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, 766848b8605Smrg void *priv_data) 767848b8605Smrg{ 768848b8605Smrg return _eglCompareConfigs(conf1, conf2, 769848b8605Smrg (const _EGLConfig *) priv_data, EGL_TRUE); 770848b8605Smrg} 771848b8605Smrg 772848b8605Smrg 773848b8605Smrg/** 774848b8605Smrg * Typical fallback routine for eglChooseConfig 775848b8605Smrg */ 776848b8605SmrgEGLBoolean 777848b8605Smrg_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, 778848b8605Smrg EGLConfig *configs, EGLint config_size, EGLint *num_configs) 779848b8605Smrg{ 780848b8605Smrg _EGLConfig criteria; 781848b8605Smrg 782848b8605Smrg if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 783848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 784848b8605Smrg 785848b8605Smrg return _eglFilterConfigArray(disp->Configs, 786848b8605Smrg configs, config_size, num_configs, 787848b8605Smrg _eglFallbackMatch, _eglFallbackCompare, 788848b8605Smrg (void *) &criteria); 789848b8605Smrg} 790848b8605Smrg 791848b8605Smrg 792848b8605Smrg/** 793848b8605Smrg * Fallback for eglGetConfigAttrib. 794848b8605Smrg */ 795848b8605SmrgEGLBoolean 796848b8605Smrg_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 797848b8605Smrg EGLint attribute, EGLint *value) 798848b8605Smrg{ 799848b8605Smrg if (!_eglIsConfigAttribValid(conf, attribute)) 800848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 801848b8605Smrg 802848b8605Smrg /* nonqueryable attributes */ 803848b8605Smrg switch (attribute) { 804848b8605Smrg case EGL_MATCH_NATIVE_PIXMAP: 805848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 806848b8605Smrg break; 807848b8605Smrg default: 808848b8605Smrg break; 809848b8605Smrg } 810848b8605Smrg 811848b8605Smrg if (!value) 812848b8605Smrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 813848b8605Smrg 814848b8605Smrg *value = _eglGetConfigKey(conf, attribute); 815848b8605Smrg return EGL_TRUE; 816848b8605Smrg} 817848b8605Smrg 818848b8605Smrg 819848b8605Smrgstatic EGLBoolean 820848b8605Smrg_eglFlattenConfig(void *elem, void *buffer) 821848b8605Smrg{ 822848b8605Smrg _EGLConfig *conf = (_EGLConfig *) elem; 823848b8605Smrg EGLConfig *handle = (EGLConfig *) buffer; 824848b8605Smrg *handle = _eglGetConfigHandle(conf); 825848b8605Smrg return EGL_TRUE; 826848b8605Smrg} 827848b8605Smrg 828848b8605Smrg/** 829848b8605Smrg * Fallback for eglGetConfigs. 830848b8605Smrg */ 831848b8605SmrgEGLBoolean 832848b8605Smrg_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, 833848b8605Smrg EGLint config_size, EGLint *num_config) 834848b8605Smrg{ 835848b8605Smrg if (!num_config) 836848b8605Smrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); 837848b8605Smrg 838848b8605Smrg *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 839848b8605Smrg sizeof(configs[0]), config_size, _eglFlattenConfig); 840848b8605Smrg 841848b8605Smrg return EGL_TRUE; 842848b8605Smrg} 843