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> 39b8e80941Smrg#include "c99_compat.h" 40b8e80941Smrg#include "util/macros.h" 41b8e80941Smrg 42848b8605Smrg#include "eglconfig.h" 43848b8605Smrg#include "egldisplay.h" 44848b8605Smrg#include "eglcurrent.h" 45848b8605Smrg#include "egllog.h" 46848b8605Smrg 47848b8605Smrg 48848b8605Smrg 49848b8605Smrg 50848b8605Smrg/** 51848b8605Smrg * Init the given _EGLconfig to default values. 52848b8605Smrg * \param id the configuration's ID. 53848b8605Smrg * 54848b8605Smrg * Note that id must be positive for the config to be valid. 55848b8605Smrg * It is also recommended that when there are N configs, their 56848b8605Smrg * IDs are from 1 to N respectively. 57848b8605Smrg */ 58848b8605Smrgvoid 59b8e80941Smrg_eglInitConfig(_EGLConfig *conf, _EGLDisplay *disp, EGLint id) 60848b8605Smrg{ 61848b8605Smrg memset(conf, 0, sizeof(*conf)); 62848b8605Smrg 63b8e80941Smrg conf->Display = disp; 64848b8605Smrg 65848b8605Smrg /* some attributes take non-zero default values */ 66848b8605Smrg conf->ConfigID = id; 67848b8605Smrg conf->ConfigCaveat = EGL_NONE; 68848b8605Smrg conf->TransparentType = EGL_NONE; 69848b8605Smrg conf->NativeVisualType = EGL_NONE; 70848b8605Smrg conf->ColorBufferType = EGL_RGB_BUFFER; 71b8e80941Smrg conf->ComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; 72848b8605Smrg} 73848b8605Smrg 74848b8605Smrg 75848b8605Smrg/** 76848b8605Smrg * Link a config to its display and return the handle of the link. 77848b8605Smrg * The handle can be passed to client directly. 78848b8605Smrg * 79848b8605Smrg * Note that we just save the ptr to the config (we don't copy the config). 80848b8605Smrg */ 81b8e80941SmrgEGLConfig 82848b8605Smrg_eglLinkConfig(_EGLConfig *conf) 83848b8605Smrg{ 84b8e80941Smrg _EGLDisplay *disp = conf->Display; 85848b8605Smrg 86848b8605Smrg /* sanity check */ 87b8e80941Smrg assert(disp); 88b8e80941Smrg assert(conf->ConfigID > 0); 89848b8605Smrg 90b8e80941Smrg if (!disp->Configs) { 91b8e80941Smrg disp->Configs = _eglCreateArray("Config", 16); 92b8e80941Smrg if (!disp->Configs) 93848b8605Smrg return (EGLConfig) NULL; 94848b8605Smrg } 95848b8605Smrg 96b8e80941Smrg _eglAppendArray(disp->Configs, (void *) conf); 97848b8605Smrg 98848b8605Smrg return (EGLConfig) conf; 99848b8605Smrg} 100848b8605Smrg 101848b8605Smrg 102848b8605Smrg/** 103848b8605Smrg * Lookup a handle to find the linked config. 104848b8605Smrg * Return NULL if the handle has no corresponding linked config. 105848b8605Smrg */ 106848b8605Smrg_EGLConfig * 107b8e80941Smrg_eglLookupConfig(EGLConfig config, _EGLDisplay *disp) 108848b8605Smrg{ 109848b8605Smrg _EGLConfig *conf; 110848b8605Smrg 111b8e80941Smrg if (!disp) 112848b8605Smrg return NULL; 113848b8605Smrg 114b8e80941Smrg conf = (_EGLConfig *) _eglFindArray(disp->Configs, (void *) config); 115848b8605Smrg if (conf) 116b8e80941Smrg assert(conf->Display == disp); 117848b8605Smrg 118848b8605Smrg return conf; 119848b8605Smrg} 120848b8605Smrg 121848b8605Smrg 122b8e80941Smrgenum type { 123848b8605Smrg ATTRIB_TYPE_INTEGER, 124848b8605Smrg ATTRIB_TYPE_BOOLEAN, 125848b8605Smrg ATTRIB_TYPE_BITMASK, 126848b8605Smrg ATTRIB_TYPE_ENUM, 127848b8605Smrg ATTRIB_TYPE_PSEUDO, /* non-queryable */ 128848b8605Smrg ATTRIB_TYPE_PLATFORM, /* platform-dependent */ 129b8e80941Smrg}; 130b8e80941Smrg 131b8e80941Smrgenum criterion { 132848b8605Smrg ATTRIB_CRITERION_EXACT, 133848b8605Smrg ATTRIB_CRITERION_ATLEAST, 134848b8605Smrg ATTRIB_CRITERION_MASK, 135848b8605Smrg ATTRIB_CRITERION_SPECIAL, 136848b8605Smrg ATTRIB_CRITERION_IGNORE 137848b8605Smrg}; 138848b8605Smrg 139848b8605Smrg 140848b8605Smrg/* EGL spec Table 3.1 and 3.4 */ 141848b8605Smrgstatic const struct { 142848b8605Smrg EGLint attr; 143b8e80941Smrg enum type type; 144b8e80941Smrg enum criterion criterion; 145848b8605Smrg EGLint default_value; 146848b8605Smrg} _eglValidationTable[] = 147848b8605Smrg{ 148848b8605Smrg /* core */ 149848b8605Smrg { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, 150848b8605Smrg ATTRIB_CRITERION_ATLEAST, 151848b8605Smrg 0 }, 152848b8605Smrg { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, 153848b8605Smrg ATTRIB_CRITERION_ATLEAST, 154848b8605Smrg 0 }, 155848b8605Smrg { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, 156848b8605Smrg ATTRIB_CRITERION_ATLEAST, 157848b8605Smrg 0 }, 158848b8605Smrg { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, 159848b8605Smrg ATTRIB_CRITERION_ATLEAST, 160848b8605Smrg 0 }, 161848b8605Smrg { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, 162848b8605Smrg ATTRIB_CRITERION_ATLEAST, 163848b8605Smrg 0 }, 164848b8605Smrg { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, 165848b8605Smrg ATTRIB_CRITERION_ATLEAST, 166848b8605Smrg 0 }, 167848b8605Smrg { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, 168848b8605Smrg ATTRIB_CRITERION_ATLEAST, 169848b8605Smrg 0 }, 170848b8605Smrg { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, 171848b8605Smrg ATTRIB_CRITERION_EXACT, 172848b8605Smrg EGL_DONT_CARE }, 173848b8605Smrg { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, 174848b8605Smrg ATTRIB_CRITERION_EXACT, 175848b8605Smrg EGL_DONT_CARE }, 176848b8605Smrg { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, 177848b8605Smrg ATTRIB_CRITERION_EXACT, 178848b8605Smrg EGL_RGB_BUFFER }, 179848b8605Smrg { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, 180848b8605Smrg ATTRIB_CRITERION_EXACT, 181848b8605Smrg EGL_DONT_CARE }, 182848b8605Smrg { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, 183848b8605Smrg ATTRIB_CRITERION_EXACT, 184848b8605Smrg EGL_DONT_CARE }, 185848b8605Smrg { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, 186848b8605Smrg ATTRIB_CRITERION_MASK, 187848b8605Smrg 0 }, 188848b8605Smrg { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, 189848b8605Smrg ATTRIB_CRITERION_ATLEAST, 190848b8605Smrg 0 }, 191848b8605Smrg { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, 192848b8605Smrg ATTRIB_CRITERION_EXACT, 193848b8605Smrg 0 }, 194848b8605Smrg { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, 195848b8605Smrg ATTRIB_CRITERION_IGNORE, 196848b8605Smrg 0 }, 197848b8605Smrg { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, 198848b8605Smrg ATTRIB_CRITERION_IGNORE, 199848b8605Smrg 0 }, 200848b8605Smrg { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, 201848b8605Smrg ATTRIB_CRITERION_IGNORE, 202848b8605Smrg 0 }, 203848b8605Smrg { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 204848b8605Smrg ATTRIB_CRITERION_EXACT, 205848b8605Smrg EGL_DONT_CARE }, 206848b8605Smrg { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 207848b8605Smrg ATTRIB_CRITERION_EXACT, 208848b8605Smrg EGL_DONT_CARE }, 209848b8605Smrg { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, 210848b8605Smrg ATTRIB_CRITERION_EXACT, 211848b8605Smrg EGL_DONT_CARE }, 212848b8605Smrg { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, 213848b8605Smrg ATTRIB_CRITERION_IGNORE, 214848b8605Smrg 0 }, 215848b8605Smrg { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, 216848b8605Smrg ATTRIB_CRITERION_EXACT, 217848b8605Smrg EGL_DONT_CARE }, 218848b8605Smrg { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, 219848b8605Smrg ATTRIB_CRITERION_MASK, 220848b8605Smrg EGL_OPENGL_ES_BIT }, 221848b8605Smrg { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, 222848b8605Smrg ATTRIB_CRITERION_ATLEAST, 223848b8605Smrg 0 }, 224848b8605Smrg { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, 225848b8605Smrg ATTRIB_CRITERION_ATLEAST, 226848b8605Smrg 0 }, 227848b8605Smrg { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, 228848b8605Smrg ATTRIB_CRITERION_ATLEAST, 229848b8605Smrg 0 }, 230848b8605Smrg { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, 231848b8605Smrg ATTRIB_CRITERION_MASK, 232848b8605Smrg EGL_WINDOW_BIT }, 233848b8605Smrg { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, 234848b8605Smrg ATTRIB_CRITERION_EXACT, 235848b8605Smrg EGL_NONE }, 236848b8605Smrg { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, 237848b8605Smrg ATTRIB_CRITERION_EXACT, 238848b8605Smrg EGL_DONT_CARE }, 239848b8605Smrg { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, 240848b8605Smrg ATTRIB_CRITERION_EXACT, 241848b8605Smrg EGL_DONT_CARE }, 242848b8605Smrg { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, 243848b8605Smrg ATTRIB_CRITERION_EXACT, 244848b8605Smrg EGL_DONT_CARE }, 245848b8605Smrg { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, 246848b8605Smrg ATTRIB_CRITERION_SPECIAL, 247848b8605Smrg EGL_NONE }, 248848b8605Smrg /* extensions */ 249848b8605Smrg { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, 250848b8605Smrg ATTRIB_CRITERION_EXACT, 251b8e80941Smrg EGL_DONT_CARE }, 252b8e80941Smrg { EGL_FRAMEBUFFER_TARGET_ANDROID, ATTRIB_TYPE_BOOLEAN, 253b8e80941Smrg ATTRIB_CRITERION_EXACT, 254b8e80941Smrg EGL_DONT_CARE }, 255b8e80941Smrg { EGL_RECORDABLE_ANDROID, ATTRIB_TYPE_BOOLEAN, 256b8e80941Smrg ATTRIB_CRITERION_EXACT, 257b8e80941Smrg EGL_DONT_CARE }, 258b8e80941Smrg { EGL_COLOR_COMPONENT_TYPE_EXT, ATTRIB_TYPE_ENUM, 259b8e80941Smrg ATTRIB_CRITERION_EXACT, 260b8e80941Smrg EGL_COLOR_COMPONENT_TYPE_FIXED_EXT }, 261848b8605Smrg}; 262848b8605Smrg 263848b8605Smrg 264848b8605Smrg/** 265848b8605Smrg * Return true if a config is valid. When for_matching is true, 266848b8605Smrg * EGL_DONT_CARE is accepted as a valid attribute value, and checks 267848b8605Smrg * for conflicting attribute values are skipped. 268848b8605Smrg * 269848b8605Smrg * Note that some attributes are platform-dependent and are not 270848b8605Smrg * checked. 271848b8605Smrg */ 272848b8605SmrgEGLBoolean 273848b8605Smrg_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) 274848b8605Smrg{ 275b8e80941Smrg _EGLDisplay *disp = conf->Display; 276848b8605Smrg EGLint i, attr, val; 277848b8605Smrg EGLBoolean valid = EGL_TRUE; 278848b8605Smrg 279848b8605Smrg /* check attributes by their types */ 280848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 281848b8605Smrg EGLint mask; 282848b8605Smrg 283848b8605Smrg attr = _eglValidationTable[i].attr; 284848b8605Smrg val = _eglGetConfigKey(conf, attr); 285848b8605Smrg 286848b8605Smrg switch (_eglValidationTable[i].type) { 287848b8605Smrg case ATTRIB_TYPE_INTEGER: 288848b8605Smrg switch (attr) { 289848b8605Smrg case EGL_CONFIG_ID: 290848b8605Smrg /* config id must be positive */ 291848b8605Smrg if (val <= 0) 292848b8605Smrg valid = EGL_FALSE; 293848b8605Smrg break; 294848b8605Smrg case EGL_SAMPLE_BUFFERS: 295848b8605Smrg /* there can be at most 1 sample buffer */ 296848b8605Smrg if (val > 1 || val < 0) 297848b8605Smrg valid = EGL_FALSE; 298848b8605Smrg break; 299848b8605Smrg default: 300848b8605Smrg if (val < 0) 301848b8605Smrg valid = EGL_FALSE; 302848b8605Smrg break; 303848b8605Smrg } 304848b8605Smrg break; 305848b8605Smrg case ATTRIB_TYPE_BOOLEAN: 306848b8605Smrg if (val != EGL_TRUE && val != EGL_FALSE) 307848b8605Smrg valid = EGL_FALSE; 308848b8605Smrg break; 309848b8605Smrg case ATTRIB_TYPE_ENUM: 310848b8605Smrg switch (attr) { 311848b8605Smrg case EGL_CONFIG_CAVEAT: 312848b8605Smrg if (val != EGL_NONE && val != EGL_SLOW_CONFIG && 313848b8605Smrg val != EGL_NON_CONFORMANT_CONFIG) 314848b8605Smrg valid = EGL_FALSE; 315848b8605Smrg break; 316848b8605Smrg case EGL_TRANSPARENT_TYPE: 317848b8605Smrg if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) 318848b8605Smrg valid = EGL_FALSE; 319848b8605Smrg break; 320848b8605Smrg case EGL_COLOR_BUFFER_TYPE: 321848b8605Smrg if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) 322848b8605Smrg valid = EGL_FALSE; 323848b8605Smrg break; 324b8e80941Smrg case EGL_COLOR_COMPONENT_TYPE_EXT: 325b8e80941Smrg if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT && 326b8e80941Smrg val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) 327b8e80941Smrg valid = EGL_FALSE; 328b8e80941Smrg break; 329848b8605Smrg default: 330b8e80941Smrg unreachable("check _eglValidationTable[]"); 331848b8605Smrg break; 332848b8605Smrg } 333848b8605Smrg break; 334848b8605Smrg case ATTRIB_TYPE_BITMASK: 335848b8605Smrg switch (attr) { 336848b8605Smrg case EGL_SURFACE_TYPE: 337848b8605Smrg mask = EGL_PBUFFER_BIT | 338848b8605Smrg EGL_PIXMAP_BIT | 339848b8605Smrg EGL_WINDOW_BIT | 340848b8605Smrg EGL_VG_COLORSPACE_LINEAR_BIT | 341848b8605Smrg EGL_VG_ALPHA_FORMAT_PRE_BIT | 342848b8605Smrg EGL_MULTISAMPLE_RESOLVE_BOX_BIT | 343848b8605Smrg EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 344b8e80941Smrg if (disp->Extensions.KHR_mutable_render_buffer) 345b8e80941Smrg mask |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR; 346848b8605Smrg break; 347848b8605Smrg case EGL_RENDERABLE_TYPE: 348848b8605Smrg case EGL_CONFORMANT: 349848b8605Smrg mask = EGL_OPENGL_ES_BIT | 350848b8605Smrg EGL_OPENVG_BIT | 351848b8605Smrg EGL_OPENGL_ES2_BIT | 352848b8605Smrg EGL_OPENGL_ES3_BIT_KHR | 353848b8605Smrg EGL_OPENGL_BIT; 354848b8605Smrg break; 355848b8605Smrg default: 356b8e80941Smrg unreachable("check _eglValidationTable[]"); 357848b8605Smrg mask = 0; 358848b8605Smrg break; 359848b8605Smrg } 360848b8605Smrg if (val & ~mask) 361848b8605Smrg valid = EGL_FALSE; 362848b8605Smrg break; 363848b8605Smrg case ATTRIB_TYPE_PLATFORM: 364848b8605Smrg /* unable to check platform-dependent attributes here */ 365848b8605Smrg break; 366848b8605Smrg case ATTRIB_TYPE_PSEUDO: 367848b8605Smrg /* pseudo attributes should not be set */ 368848b8605Smrg if (val != 0) 369848b8605Smrg valid = EGL_FALSE; 370848b8605Smrg break; 371848b8605Smrg } 372848b8605Smrg 373848b8605Smrg if (!valid && for_matching) { 374848b8605Smrg /* accept EGL_DONT_CARE as a valid value */ 375848b8605Smrg if (val == EGL_DONT_CARE) 376848b8605Smrg valid = EGL_TRUE; 377848b8605Smrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 378848b8605Smrg valid = EGL_TRUE; 379848b8605Smrg } 380848b8605Smrg if (!valid) { 381848b8605Smrg _eglLog(_EGL_DEBUG, 382848b8605Smrg "attribute 0x%04x has an invalid value 0x%x", attr, val); 383848b8605Smrg break; 384848b8605Smrg } 385848b8605Smrg } 386848b8605Smrg 387848b8605Smrg /* any invalid attribute value should have been catched */ 388848b8605Smrg if (!valid || for_matching) 389848b8605Smrg return valid; 390848b8605Smrg 391848b8605Smrg /* now check for conflicting attribute values */ 392848b8605Smrg 393848b8605Smrg switch (conf->ColorBufferType) { 394848b8605Smrg case EGL_RGB_BUFFER: 395848b8605Smrg if (conf->LuminanceSize) 396848b8605Smrg valid = EGL_FALSE; 397848b8605Smrg if (conf->RedSize + conf->GreenSize + 398848b8605Smrg conf->BlueSize + conf->AlphaSize != conf->BufferSize) 399848b8605Smrg valid = EGL_FALSE; 400848b8605Smrg break; 401848b8605Smrg case EGL_LUMINANCE_BUFFER: 402848b8605Smrg if (conf->RedSize || conf->GreenSize || conf->BlueSize) 403848b8605Smrg valid = EGL_FALSE; 404848b8605Smrg if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 405848b8605Smrg valid = EGL_FALSE; 406848b8605Smrg break; 407848b8605Smrg } 408848b8605Smrg if (!valid) { 409848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 410848b8605Smrg return EGL_FALSE; 411848b8605Smrg } 412848b8605Smrg 413848b8605Smrg if (!conf->SampleBuffers && conf->Samples) 414848b8605Smrg valid = EGL_FALSE; 415848b8605Smrg if (!valid) { 416848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 417848b8605Smrg return EGL_FALSE; 418848b8605Smrg } 419848b8605Smrg 420848b8605Smrg if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 421848b8605Smrg if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 422848b8605Smrg valid = EGL_FALSE; 423848b8605Smrg } 424848b8605Smrg if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 425848b8605Smrg if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 426848b8605Smrg valid = EGL_FALSE; 427848b8605Smrg } 428848b8605Smrg if (!valid) { 429848b8605Smrg _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 430848b8605Smrg return EGL_FALSE; 431848b8605Smrg } 432848b8605Smrg 433848b8605Smrg return valid; 434848b8605Smrg} 435848b8605Smrg 436848b8605Smrg 437848b8605Smrg/** 438848b8605Smrg * Return true if a config matches the criteria. This and 439848b8605Smrg * _eglParseConfigAttribList together implement the algorithm 440848b8605Smrg * described in "Selection of EGLConfigs". 441848b8605Smrg * 442848b8605Smrg * Note that attributes that are special (currently, only 443848b8605Smrg * EGL_MATCH_NATIVE_PIXMAP) are ignored. 444848b8605Smrg */ 445848b8605SmrgEGLBoolean 446848b8605Smrg_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 447848b8605Smrg{ 448848b8605Smrg EGLint attr, val, i; 449848b8605Smrg EGLBoolean matched = EGL_TRUE; 450848b8605Smrg 451848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 452848b8605Smrg EGLint cmp; 453848b8605Smrg if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 454848b8605Smrg continue; 455848b8605Smrg 456848b8605Smrg attr = _eglValidationTable[i].attr; 457848b8605Smrg cmp = _eglGetConfigKey(criteria, attr); 458848b8605Smrg if (cmp == EGL_DONT_CARE) 459848b8605Smrg continue; 460848b8605Smrg 461848b8605Smrg val = _eglGetConfigKey(conf, attr); 462848b8605Smrg switch (_eglValidationTable[i].criterion) { 463848b8605Smrg case ATTRIB_CRITERION_EXACT: 464848b8605Smrg if (val != cmp) 465848b8605Smrg matched = EGL_FALSE; 466848b8605Smrg break; 467848b8605Smrg case ATTRIB_CRITERION_ATLEAST: 468848b8605Smrg if (val < cmp) 469848b8605Smrg matched = EGL_FALSE; 470848b8605Smrg break; 471848b8605Smrg case ATTRIB_CRITERION_MASK: 472848b8605Smrg if ((val & cmp) != cmp) 473848b8605Smrg matched = EGL_FALSE; 474848b8605Smrg break; 475848b8605Smrg case ATTRIB_CRITERION_SPECIAL: 476848b8605Smrg /* ignored here */ 477848b8605Smrg break; 478b8e80941Smrg case ATTRIB_CRITERION_IGNORE: 479b8e80941Smrg unreachable("already handled above"); 480848b8605Smrg break; 481848b8605Smrg } 482848b8605Smrg 483848b8605Smrg if (!matched) { 484848b8605Smrg#ifndef DEBUG 485848b8605Smrg /* only print the common errors when DEBUG is not defined */ 486848b8605Smrg if (attr != EGL_RENDERABLE_TYPE) 487848b8605Smrg break; 488848b8605Smrg#endif 489848b8605Smrg _eglLog(_EGL_DEBUG, 490848b8605Smrg "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 491848b8605Smrg val, attr, cmp); 492848b8605Smrg break; 493848b8605Smrg } 494848b8605Smrg } 495848b8605Smrg 496848b8605Smrg return matched; 497848b8605Smrg} 498848b8605Smrg 499b8e80941Smrgstatic inline EGLBoolean 500848b8605Smrg_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 501848b8605Smrg{ 502848b8605Smrg if (_eglOffsetOfConfig(attr) < 0) 503848b8605Smrg return EGL_FALSE; 504848b8605Smrg 505848b8605Smrg switch (attr) { 506848b8605Smrg case EGL_Y_INVERTED_NOK: 507848b8605Smrg return conf->Display->Extensions.NOK_texture_from_pixmap; 508b8e80941Smrg case EGL_FRAMEBUFFER_TARGET_ANDROID: 509b8e80941Smrg return conf->Display->Extensions.ANDROID_framebuffer_target; 510b8e80941Smrg case EGL_RECORDABLE_ANDROID: 511b8e80941Smrg return conf->Display->Extensions.ANDROID_recordable; 512848b8605Smrg default: 513848b8605Smrg break; 514848b8605Smrg } 515848b8605Smrg 516848b8605Smrg return EGL_TRUE; 517848b8605Smrg} 518848b8605Smrg 519848b8605Smrg/** 520848b8605Smrg * Initialize a criteria config from the given attribute list. 521848b8605Smrg * Return EGL_FALSE if any of the attribute is invalid. 522848b8605Smrg */ 523848b8605SmrgEGLBoolean 524b8e80941Smrg_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp, 525848b8605Smrg const EGLint *attrib_list) 526848b8605Smrg{ 527848b8605Smrg EGLint attr, val, i; 528848b8605Smrg 529b8e80941Smrg _eglInitConfig(conf, disp, EGL_DONT_CARE); 530848b8605Smrg 531848b8605Smrg /* reset to default values */ 532848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 533848b8605Smrg attr = _eglValidationTable[i].attr; 534848b8605Smrg val = _eglValidationTable[i].default_value; 535848b8605Smrg _eglSetConfigKey(conf, attr, val); 536848b8605Smrg } 537848b8605Smrg 538848b8605Smrg /* parse the list */ 539848b8605Smrg for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 540848b8605Smrg attr = attrib_list[i]; 541848b8605Smrg val = attrib_list[i + 1]; 542848b8605Smrg 543848b8605Smrg if (!_eglIsConfigAttribValid(conf, attr)) 544b8e80941Smrg return EGL_FALSE; 545848b8605Smrg 546848b8605Smrg _eglSetConfigKey(conf, attr, val); 547848b8605Smrg } 548848b8605Smrg 549848b8605Smrg if (!_eglValidateConfig(conf, EGL_TRUE)) 550848b8605Smrg return EGL_FALSE; 551848b8605Smrg 552848b8605Smrg /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */ 553848b8605Smrg if (conf->Level == EGL_DONT_CARE || 554848b8605Smrg conf->MatchNativePixmap == EGL_DONT_CARE) 555848b8605Smrg return EGL_FALSE; 556848b8605Smrg 557848b8605Smrg /* ignore other attributes when EGL_CONFIG_ID is given */ 558848b8605Smrg if (conf->ConfigID != EGL_DONT_CARE) { 559848b8605Smrg for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 560848b8605Smrg attr = _eglValidationTable[i].attr; 561848b8605Smrg if (attr != EGL_CONFIG_ID) 562848b8605Smrg _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 563848b8605Smrg } 564848b8605Smrg } 565848b8605Smrg else { 566848b8605Smrg if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 567848b8605Smrg conf->NativeVisualType = EGL_DONT_CARE; 568848b8605Smrg 569848b8605Smrg if (conf->TransparentType == EGL_NONE) { 570848b8605Smrg conf->TransparentRedValue = EGL_DONT_CARE; 571848b8605Smrg conf->TransparentGreenValue = EGL_DONT_CARE; 572848b8605Smrg conf->TransparentBlueValue = EGL_DONT_CARE; 573848b8605Smrg } 574848b8605Smrg } 575848b8605Smrg 576848b8605Smrg return EGL_TRUE; 577848b8605Smrg} 578848b8605Smrg 579848b8605Smrg 580848b8605Smrg/** 581848b8605Smrg * Decide the ordering of conf1 and conf2, under the given criteria. 582848b8605Smrg * When compare_id is true, this implements the algorithm described 583848b8605Smrg * in "Sorting of EGLConfigs". When compare_id is false, 584848b8605Smrg * EGL_CONFIG_ID is not compared. 585848b8605Smrg * 586848b8605Smrg * It returns a negative integer if conf1 is considered to come 587848b8605Smrg * before conf2; a positive integer if conf2 is considered to come 588848b8605Smrg * before conf1; zero if the ordering cannot be decided. 589848b8605Smrg * 590848b8605Smrg * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 591848b8605Smrg * ignored here. 592848b8605Smrg */ 593848b8605SmrgEGLint 594848b8605Smrg_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 595848b8605Smrg const _EGLConfig *criteria, EGLBoolean compare_id) 596848b8605Smrg{ 597848b8605Smrg const EGLint compare_attribs[] = { 598848b8605Smrg EGL_BUFFER_SIZE, 599848b8605Smrg EGL_SAMPLE_BUFFERS, 600848b8605Smrg EGL_SAMPLES, 601848b8605Smrg EGL_DEPTH_SIZE, 602848b8605Smrg EGL_STENCIL_SIZE, 603848b8605Smrg EGL_ALPHA_MASK_SIZE, 604848b8605Smrg }; 605848b8605Smrg EGLint val1, val2; 606848b8605Smrg EGLint i; 607848b8605Smrg 608848b8605Smrg if (conf1 == conf2) 609848b8605Smrg return 0; 610848b8605Smrg 611848b8605Smrg /* the enum values have the desired ordering */ 612b8e80941Smrg STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG); 613b8e80941Smrg STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 614848b8605Smrg val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 615848b8605Smrg if (val1) 616848b8605Smrg return val1; 617848b8605Smrg 618848b8605Smrg /* the enum values have the desired ordering */ 619b8e80941Smrg STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 620848b8605Smrg val1 = conf1->ColorBufferType - conf2->ColorBufferType; 621848b8605Smrg if (val1) 622848b8605Smrg return val1; 623848b8605Smrg 624848b8605Smrg if (criteria) { 625848b8605Smrg val1 = val2 = 0; 626848b8605Smrg if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 627848b8605Smrg if (criteria->RedSize > 0) { 628848b8605Smrg val1 += conf1->RedSize; 629848b8605Smrg val2 += conf2->RedSize; 630848b8605Smrg } 631848b8605Smrg if (criteria->GreenSize > 0) { 632848b8605Smrg val1 += conf1->GreenSize; 633848b8605Smrg val2 += conf2->GreenSize; 634848b8605Smrg } 635848b8605Smrg if (criteria->BlueSize > 0) { 636848b8605Smrg val1 += conf1->BlueSize; 637848b8605Smrg val2 += conf2->BlueSize; 638848b8605Smrg } 639848b8605Smrg } 640848b8605Smrg else { 641848b8605Smrg if (criteria->LuminanceSize > 0) { 642848b8605Smrg val1 += conf1->LuminanceSize; 643848b8605Smrg val2 += conf2->LuminanceSize; 644848b8605Smrg } 645848b8605Smrg } 646848b8605Smrg if (criteria->AlphaSize > 0) { 647848b8605Smrg val1 += conf1->AlphaSize; 648848b8605Smrg val2 += conf2->AlphaSize; 649848b8605Smrg } 650848b8605Smrg } 651848b8605Smrg else { 652848b8605Smrg /* assume the default criteria, which gives no specific ordering */ 653848b8605Smrg val1 = val2 = 0; 654848b8605Smrg } 655848b8605Smrg 656848b8605Smrg /* for color bits, larger one is preferred */ 657848b8605Smrg if (val1 != val2) 658848b8605Smrg return (val2 - val1); 659848b8605Smrg 660848b8605Smrg for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 661848b8605Smrg val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 662848b8605Smrg val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 663848b8605Smrg if (val1 != val2) 664848b8605Smrg return (val1 - val2); 665848b8605Smrg } 666848b8605Smrg 667848b8605Smrg /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 668848b8605Smrg 669848b8605Smrg return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 670848b8605Smrg} 671848b8605Smrg 672848b8605Smrg 673b8e80941Smrgstatic inline 674848b8605Smrgvoid _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 675848b8605Smrg{ 676848b8605Smrg const _EGLConfig *tmp = *conf1; 677848b8605Smrg *conf1 = *conf2; 678848b8605Smrg *conf2 = tmp; 679848b8605Smrg} 680848b8605Smrg 681848b8605Smrg 682848b8605Smrg/** 683848b8605Smrg * Quick sort an array of configs. This differs from the standard 684848b8605Smrg * qsort() in that the compare function accepts an additional 685848b8605Smrg * argument. 686848b8605Smrg */ 687848b8605Smrgstatic void 688848b8605Smrg_eglSortConfigs(const _EGLConfig **configs, EGLint count, 689848b8605Smrg EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 690848b8605Smrg void *), 691848b8605Smrg void *priv_data) 692848b8605Smrg{ 693848b8605Smrg const EGLint pivot = 0; 694848b8605Smrg EGLint i, j; 695848b8605Smrg 696848b8605Smrg if (count <= 1) 697848b8605Smrg return; 698848b8605Smrg 699848b8605Smrg _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 700848b8605Smrg i = 1; 701848b8605Smrg j = count - 1; 702848b8605Smrg do { 703848b8605Smrg while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 704848b8605Smrg i++; 705848b8605Smrg while (compare(configs[j], configs[pivot], priv_data) > 0) 706848b8605Smrg j--; 707848b8605Smrg if (i < j) { 708848b8605Smrg _eglSwapConfigs(&configs[i], &configs[j]); 709848b8605Smrg i++; 710848b8605Smrg j--; 711848b8605Smrg } 712848b8605Smrg else if (i == j) { 713848b8605Smrg i++; 714848b8605Smrg j--; 715848b8605Smrg break; 716848b8605Smrg } 717848b8605Smrg } while (i <= j); 718848b8605Smrg _eglSwapConfigs(&configs[pivot], &configs[j]); 719848b8605Smrg 720848b8605Smrg _eglSortConfigs(configs, j, compare, priv_data); 721848b8605Smrg _eglSortConfigs(configs + i, count - i, compare, priv_data); 722848b8605Smrg} 723848b8605Smrg 724848b8605Smrg 725848b8605Smrg/** 726848b8605Smrg * A helper function for implementing eglChooseConfig. See _eglFilterArray and 727848b8605Smrg * _eglSortConfigs for the meanings of match and compare. 728848b8605Smrg */ 729848b8605SmrgEGLBoolean 730848b8605Smrg_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, 731848b8605Smrg EGLint config_size, EGLint *num_configs, 732848b8605Smrg EGLBoolean (*match)(const _EGLConfig *, void *), 733848b8605Smrg EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 734848b8605Smrg void *), 735848b8605Smrg void *priv_data) 736848b8605Smrg{ 737848b8605Smrg _EGLConfig **configList; 738848b8605Smrg EGLint i, count; 739848b8605Smrg 740848b8605Smrg if (!num_configs) 741b8e80941Smrg return _eglError(EGL_BAD_PARAMETER, "eglChooseConfig"); 742848b8605Smrg 743848b8605Smrg /* get the number of matched configs */ 744848b8605Smrg count = _eglFilterArray(array, NULL, 0, 745848b8605Smrg (_EGLArrayForEach) match, priv_data); 746848b8605Smrg if (!count) { 747848b8605Smrg *num_configs = count; 748848b8605Smrg return EGL_TRUE; 749848b8605Smrg } 750848b8605Smrg 751848b8605Smrg configList = malloc(sizeof(*configList) * count); 752848b8605Smrg if (!configList) 753848b8605Smrg return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 754848b8605Smrg 755848b8605Smrg /* get the matched configs */ 756848b8605Smrg _eglFilterArray(array, (void **) configList, count, 757848b8605Smrg (_EGLArrayForEach) match, priv_data); 758848b8605Smrg 759848b8605Smrg /* perform sorting of configs */ 760848b8605Smrg if (configs && count) { 761848b8605Smrg _eglSortConfigs((const _EGLConfig **) configList, count, 762848b8605Smrg compare, priv_data); 763848b8605Smrg count = MIN2(count, config_size); 764848b8605Smrg for (i = 0; i < count; i++) 765848b8605Smrg configs[i] = _eglGetConfigHandle(configList[i]); 766848b8605Smrg } 767848b8605Smrg 768848b8605Smrg free(configList); 769848b8605Smrg 770848b8605Smrg *num_configs = count; 771848b8605Smrg 772848b8605Smrg return EGL_TRUE; 773848b8605Smrg} 774848b8605Smrg 775848b8605Smrg 776848b8605Smrgstatic EGLBoolean 777848b8605Smrg_eglFallbackMatch(const _EGLConfig *conf, void *priv_data) 778848b8605Smrg{ 779848b8605Smrg return _eglMatchConfig(conf, (const _EGLConfig *) priv_data); 780848b8605Smrg} 781848b8605Smrg 782848b8605Smrg 783848b8605Smrgstatic EGLint 784848b8605Smrg_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, 785848b8605Smrg void *priv_data) 786848b8605Smrg{ 787848b8605Smrg return _eglCompareConfigs(conf1, conf2, 788848b8605Smrg (const _EGLConfig *) priv_data, EGL_TRUE); 789848b8605Smrg} 790848b8605Smrg 791848b8605Smrg 792848b8605Smrg/** 793848b8605Smrg * Typical fallback routine for eglChooseConfig 794848b8605Smrg */ 795848b8605SmrgEGLBoolean 796848b8605Smrg_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, 797848b8605Smrg EGLConfig *configs, EGLint config_size, EGLint *num_configs) 798848b8605Smrg{ 799848b8605Smrg _EGLConfig criteria; 800848b8605Smrg 801848b8605Smrg if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 802848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 803848b8605Smrg 804848b8605Smrg return _eglFilterConfigArray(disp->Configs, 805848b8605Smrg configs, config_size, num_configs, 806848b8605Smrg _eglFallbackMatch, _eglFallbackCompare, 807848b8605Smrg (void *) &criteria); 808848b8605Smrg} 809848b8605Smrg 810848b8605Smrg 811848b8605Smrg/** 812848b8605Smrg * Fallback for eglGetConfigAttrib. 813848b8605Smrg */ 814848b8605SmrgEGLBoolean 815b8e80941Smrg_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, 816848b8605Smrg EGLint attribute, EGLint *value) 817848b8605Smrg{ 818848b8605Smrg if (!_eglIsConfigAttribValid(conf, attribute)) 819848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 820848b8605Smrg 821848b8605Smrg /* nonqueryable attributes */ 822848b8605Smrg switch (attribute) { 823848b8605Smrg case EGL_MATCH_NATIVE_PIXMAP: 824848b8605Smrg return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 825848b8605Smrg break; 826848b8605Smrg default: 827848b8605Smrg break; 828848b8605Smrg } 829848b8605Smrg 830848b8605Smrg if (!value) 831848b8605Smrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 832848b8605Smrg 833848b8605Smrg *value = _eglGetConfigKey(conf, attribute); 834848b8605Smrg return EGL_TRUE; 835848b8605Smrg} 836848b8605Smrg 837848b8605Smrg 838848b8605Smrgstatic EGLBoolean 839848b8605Smrg_eglFlattenConfig(void *elem, void *buffer) 840848b8605Smrg{ 841848b8605Smrg _EGLConfig *conf = (_EGLConfig *) elem; 842848b8605Smrg EGLConfig *handle = (EGLConfig *) buffer; 843848b8605Smrg *handle = _eglGetConfigHandle(conf); 844848b8605Smrg return EGL_TRUE; 845848b8605Smrg} 846848b8605Smrg 847848b8605Smrg/** 848848b8605Smrg * Fallback for eglGetConfigs. 849848b8605Smrg */ 850848b8605SmrgEGLBoolean 851848b8605Smrg_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, 852848b8605Smrg EGLint config_size, EGLint *num_config) 853848b8605Smrg{ 854848b8605Smrg if (!num_config) 855848b8605Smrg return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); 856848b8605Smrg 857848b8605Smrg *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 858848b8605Smrg sizeof(configs[0]), config_size, _eglFlattenConfig); 859848b8605Smrg 860848b8605Smrg return EGL_TRUE; 861848b8605Smrg} 862