1/************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 5 * Copyright 2010-2011 LunarG, Inc. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 30 31/** 32 * EGL Configuration (pixel format) functions. 33 */ 34 35 36#include <stdlib.h> 37#include <string.h> 38#include <assert.h> 39#include "util/macros.h" 40 41#include "eglconfig.h" 42#include "eglconfigdebug.h" 43#include "egldisplay.h" 44#include "eglcurrent.h" 45#include "egllog.h" 46 47 48 49 50/** 51 * Init the given _EGLconfig to default values. 52 * \param id the configuration's ID. 53 * 54 * Note that id must be positive for the config to be valid. 55 * It is also recommended that when there are N configs, their 56 * IDs are from 1 to N respectively. 57 */ 58void 59_eglInitConfig(_EGLConfig *conf, _EGLDisplay *disp, EGLint id) 60{ 61 memset(conf, 0, sizeof(*conf)); 62 63 conf->Display = disp; 64 65 /* some attributes take non-zero default values */ 66 conf->ConfigID = id; 67 conf->ConfigCaveat = EGL_NONE; 68 conf->TransparentType = EGL_NONE; 69 conf->NativeVisualType = EGL_NONE; 70 conf->ColorBufferType = EGL_RGB_BUFFER; 71 conf->ComponentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; 72} 73 74 75/** 76 * Link a config to its display and return the handle of the link. 77 * The handle can be passed to client directly. 78 * 79 * Note that we just save the ptr to the config (we don't copy the config). 80 */ 81EGLConfig 82_eglLinkConfig(_EGLConfig *conf) 83{ 84 _EGLDisplay *disp = conf->Display; 85 86 /* sanity check */ 87 assert(disp); 88 assert(conf->ConfigID > 0); 89 90 if (!disp->Configs) { 91 disp->Configs = _eglCreateArray("Config", 16); 92 if (!disp->Configs) 93 return (EGLConfig) NULL; 94 } 95 96 _eglAppendArray(disp->Configs, (void *) conf); 97 98 return (EGLConfig) conf; 99} 100 101 102/** 103 * Lookup a handle to find the linked config. 104 * Return NULL if the handle has no corresponding linked config. 105 */ 106_EGLConfig * 107_eglLookupConfig(EGLConfig config, _EGLDisplay *disp) 108{ 109 _EGLConfig *conf; 110 111 if (!disp) 112 return NULL; 113 114 conf = (_EGLConfig *) _eglFindArray(disp->Configs, (void *) config); 115 if (conf) 116 assert(conf->Display == disp); 117 118 return conf; 119} 120 121 122enum type { 123 ATTRIB_TYPE_INTEGER, 124 ATTRIB_TYPE_BOOLEAN, 125 ATTRIB_TYPE_BITMASK, 126 ATTRIB_TYPE_ENUM, 127 ATTRIB_TYPE_PSEUDO, /* non-queryable */ 128 ATTRIB_TYPE_PLATFORM, /* platform-dependent */ 129}; 130 131enum criterion { 132 ATTRIB_CRITERION_EXACT, 133 ATTRIB_CRITERION_ATLEAST, 134 ATTRIB_CRITERION_MASK, 135 ATTRIB_CRITERION_SPECIAL, 136 ATTRIB_CRITERION_IGNORE 137}; 138 139 140/* EGL spec Table 3.1 and 3.4 */ 141static const struct { 142 EGLint attr; 143 enum type type; 144 enum criterion criterion; 145 EGLint default_value; 146} _eglValidationTable[] = 147{ 148 /* core */ 149 { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER, 150 ATTRIB_CRITERION_ATLEAST, 151 0 }, 152 { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER, 153 ATTRIB_CRITERION_ATLEAST, 154 0 }, 155 { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER, 156 ATTRIB_CRITERION_ATLEAST, 157 0 }, 158 { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER, 159 ATTRIB_CRITERION_ATLEAST, 160 0 }, 161 { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER, 162 ATTRIB_CRITERION_ATLEAST, 163 0 }, 164 { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER, 165 ATTRIB_CRITERION_ATLEAST, 166 0 }, 167 { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER, 168 ATTRIB_CRITERION_ATLEAST, 169 0 }, 170 { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN, 171 ATTRIB_CRITERION_EXACT, 172 EGL_DONT_CARE }, 173 { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN, 174 ATTRIB_CRITERION_EXACT, 175 EGL_DONT_CARE }, 176 { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM, 177 ATTRIB_CRITERION_EXACT, 178 EGL_RGB_BUFFER }, 179 { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM, 180 ATTRIB_CRITERION_EXACT, 181 EGL_DONT_CARE }, 182 { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER, 183 ATTRIB_CRITERION_EXACT, 184 EGL_DONT_CARE }, 185 { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK, 186 ATTRIB_CRITERION_MASK, 187 0 }, 188 { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER, 189 ATTRIB_CRITERION_ATLEAST, 190 0 }, 191 { EGL_LEVEL, ATTRIB_TYPE_PLATFORM, 192 ATTRIB_CRITERION_EXACT, 193 0 }, 194 { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER, 195 ATTRIB_CRITERION_IGNORE, 196 0 }, 197 { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER, 198 ATTRIB_CRITERION_IGNORE, 199 0 }, 200 { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER, 201 ATTRIB_CRITERION_IGNORE, 202 0 }, 203 { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 204 ATTRIB_CRITERION_EXACT, 205 EGL_DONT_CARE }, 206 { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER, 207 ATTRIB_CRITERION_EXACT, 208 EGL_DONT_CARE }, 209 { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN, 210 ATTRIB_CRITERION_EXACT, 211 EGL_DONT_CARE }, 212 { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM, 213 ATTRIB_CRITERION_IGNORE, 214 0 }, 215 { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM, 216 ATTRIB_CRITERION_EXACT, 217 EGL_DONT_CARE }, 218 { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK, 219 ATTRIB_CRITERION_MASK, 220 EGL_OPENGL_ES_BIT }, 221 { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER, 222 ATTRIB_CRITERION_ATLEAST, 223 0 }, 224 { EGL_SAMPLES, ATTRIB_TYPE_INTEGER, 225 ATTRIB_CRITERION_ATLEAST, 226 0 }, 227 { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER, 228 ATTRIB_CRITERION_ATLEAST, 229 0 }, 230 { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK, 231 ATTRIB_CRITERION_MASK, 232 EGL_WINDOW_BIT }, 233 { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM, 234 ATTRIB_CRITERION_EXACT, 235 EGL_NONE }, 236 { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER, 237 ATTRIB_CRITERION_EXACT, 238 EGL_DONT_CARE }, 239 { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER, 240 ATTRIB_CRITERION_EXACT, 241 EGL_DONT_CARE }, 242 { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER, 243 ATTRIB_CRITERION_EXACT, 244 EGL_DONT_CARE }, 245 { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO, 246 ATTRIB_CRITERION_SPECIAL, 247 EGL_NONE }, 248 /* extensions */ 249 { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN, 250 ATTRIB_CRITERION_EXACT, 251 EGL_DONT_CARE }, 252 { EGL_FRAMEBUFFER_TARGET_ANDROID, ATTRIB_TYPE_BOOLEAN, 253 ATTRIB_CRITERION_EXACT, 254 EGL_DONT_CARE }, 255 { EGL_RECORDABLE_ANDROID, ATTRIB_TYPE_BOOLEAN, 256 ATTRIB_CRITERION_EXACT, 257 EGL_DONT_CARE }, 258 { EGL_COLOR_COMPONENT_TYPE_EXT, ATTRIB_TYPE_ENUM, 259 ATTRIB_CRITERION_EXACT, 260 EGL_COLOR_COMPONENT_TYPE_FIXED_EXT }, 261}; 262 263 264/** 265 * Return true if a config is valid. When for_matching is true, 266 * EGL_DONT_CARE is accepted as a valid attribute value, and checks 267 * for conflicting attribute values are skipped. 268 * 269 * Note that some attributes are platform-dependent and are not 270 * checked. 271 */ 272EGLBoolean 273_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) 274{ 275 _EGLDisplay *disp = conf->Display; 276 EGLint i, attr, val; 277 EGLBoolean valid = EGL_TRUE; 278 279 /* check attributes by their types */ 280 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 281 EGLint mask; 282 283 attr = _eglValidationTable[i].attr; 284 val = _eglGetConfigKey(conf, attr); 285 286 switch (_eglValidationTable[i].type) { 287 case ATTRIB_TYPE_INTEGER: 288 switch (attr) { 289 case EGL_CONFIG_ID: 290 /* config id must be positive */ 291 if (val <= 0) 292 valid = EGL_FALSE; 293 break; 294 case EGL_SAMPLE_BUFFERS: 295 /* there can be at most 1 sample buffer */ 296 if (val > 1 || val < 0) 297 valid = EGL_FALSE; 298 break; 299 default: 300 if (val < 0) 301 valid = EGL_FALSE; 302 break; 303 } 304 break; 305 case ATTRIB_TYPE_BOOLEAN: 306 if (val != EGL_TRUE && val != EGL_FALSE) 307 valid = EGL_FALSE; 308 break; 309 case ATTRIB_TYPE_ENUM: 310 switch (attr) { 311 case EGL_CONFIG_CAVEAT: 312 if (val != EGL_NONE && val != EGL_SLOW_CONFIG && 313 val != EGL_NON_CONFORMANT_CONFIG) 314 valid = EGL_FALSE; 315 break; 316 case EGL_TRANSPARENT_TYPE: 317 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) 318 valid = EGL_FALSE; 319 break; 320 case EGL_COLOR_BUFFER_TYPE: 321 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) 322 valid = EGL_FALSE; 323 break; 324 case EGL_COLOR_COMPONENT_TYPE_EXT: 325 if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT && 326 val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) 327 valid = EGL_FALSE; 328 break; 329 default: 330 unreachable("check _eglValidationTable[]"); 331 break; 332 } 333 break; 334 case ATTRIB_TYPE_BITMASK: 335 switch (attr) { 336 case EGL_SURFACE_TYPE: 337 mask = EGL_PBUFFER_BIT | 338 EGL_PIXMAP_BIT | 339 EGL_WINDOW_BIT | 340 EGL_VG_COLORSPACE_LINEAR_BIT | 341 EGL_VG_ALPHA_FORMAT_PRE_BIT | 342 EGL_MULTISAMPLE_RESOLVE_BOX_BIT | 343 EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 344 if (disp->Extensions.KHR_mutable_render_buffer) 345 mask |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR; 346 break; 347 case EGL_RENDERABLE_TYPE: 348 case EGL_CONFORMANT: 349 mask = EGL_OPENGL_ES_BIT | 350 EGL_OPENVG_BIT | 351 EGL_OPENGL_ES2_BIT | 352 EGL_OPENGL_ES3_BIT_KHR | 353 EGL_OPENGL_BIT; 354 break; 355 default: 356 unreachable("check _eglValidationTable[]"); 357 mask = 0; 358 break; 359 } 360 if (val & ~mask) 361 valid = EGL_FALSE; 362 break; 363 case ATTRIB_TYPE_PLATFORM: 364 /* unable to check platform-dependent attributes here */ 365 break; 366 case ATTRIB_TYPE_PSEUDO: 367 /* pseudo attributes should not be set */ 368 if (val != 0) 369 valid = EGL_FALSE; 370 break; 371 } 372 373 if (!valid && for_matching) { 374 /* accept EGL_DONT_CARE as a valid value */ 375 if (val == EGL_DONT_CARE) 376 valid = EGL_TRUE; 377 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 378 valid = EGL_TRUE; 379 } 380 if (!valid) { 381 _eglLog(_EGL_DEBUG, 382 "attribute 0x%04x has an invalid value 0x%x", attr, val); 383 break; 384 } 385 } 386 387 /* any invalid attribute value should have been catched */ 388 if (!valid || for_matching) 389 return valid; 390 391 /* now check for conflicting attribute values */ 392 393 switch (conf->ColorBufferType) { 394 case EGL_RGB_BUFFER: 395 if (conf->LuminanceSize) 396 valid = EGL_FALSE; 397 if (conf->RedSize + conf->GreenSize + 398 conf->BlueSize + conf->AlphaSize != conf->BufferSize) 399 valid = EGL_FALSE; 400 break; 401 case EGL_LUMINANCE_BUFFER: 402 if (conf->RedSize || conf->GreenSize || conf->BlueSize) 403 valid = EGL_FALSE; 404 if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 405 valid = EGL_FALSE; 406 break; 407 } 408 if (!valid) { 409 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 410 return EGL_FALSE; 411 } 412 413 if (!conf->SampleBuffers && conf->Samples) 414 valid = EGL_FALSE; 415 if (!valid) { 416 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 417 return EGL_FALSE; 418 } 419 420 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 421 if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 422 valid = EGL_FALSE; 423 } 424 if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 425 if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 426 valid = EGL_FALSE; 427 } 428 if (!valid) { 429 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 430 return EGL_FALSE; 431 } 432 433 return valid; 434} 435 436 437/** 438 * Return true if a config matches the criteria. This and 439 * _eglParseConfigAttribList together implement the algorithm 440 * described in "Selection of EGLConfigs". 441 * 442 * Note that attributes that are special (currently, only 443 * EGL_MATCH_NATIVE_PIXMAP) are ignored. 444 */ 445EGLBoolean 446_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 447{ 448 EGLint attr, val, i; 449 EGLBoolean matched = EGL_TRUE; 450 451 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 452 EGLint cmp; 453 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 454 continue; 455 456 attr = _eglValidationTable[i].attr; 457 cmp = _eglGetConfigKey(criteria, attr); 458 if (cmp == EGL_DONT_CARE) 459 continue; 460 461 val = _eglGetConfigKey(conf, attr); 462 switch (_eglValidationTable[i].criterion) { 463 case ATTRIB_CRITERION_EXACT: 464 if (val != cmp) 465 matched = EGL_FALSE; 466 break; 467 case ATTRIB_CRITERION_ATLEAST: 468 if (val < cmp) 469 matched = EGL_FALSE; 470 break; 471 case ATTRIB_CRITERION_MASK: 472 if ((val & cmp) != cmp) 473 matched = EGL_FALSE; 474 break; 475 case ATTRIB_CRITERION_SPECIAL: 476 /* ignored here */ 477 break; 478 case ATTRIB_CRITERION_IGNORE: 479 unreachable("already handled above"); 480 break; 481 } 482 483 if (!matched) { 484#ifndef DEBUG 485 /* only print the common errors when DEBUG is not defined */ 486 if (attr != EGL_RENDERABLE_TYPE) 487 break; 488#endif 489 _eglLog(_EGL_DEBUG, 490 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 491 val, attr, cmp); 492 break; 493 } 494 } 495 496 return matched; 497} 498 499static inline EGLBoolean 500_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 501{ 502 if (_eglOffsetOfConfig(attr) < 0) 503 return EGL_FALSE; 504 505 switch (attr) { 506 case EGL_Y_INVERTED_NOK: 507 return conf->Display->Extensions.NOK_texture_from_pixmap; 508 case EGL_FRAMEBUFFER_TARGET_ANDROID: 509 return conf->Display->Extensions.ANDROID_framebuffer_target; 510 case EGL_RECORDABLE_ANDROID: 511 return conf->Display->Extensions.ANDROID_recordable; 512 default: 513 break; 514 } 515 516 return EGL_TRUE; 517} 518 519/** 520 * Initialize a criteria config from the given attribute list. 521 * Return EGL_FALSE if any of the attribute is invalid. 522 */ 523EGLBoolean 524_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp, 525 const EGLint *attrib_list) 526{ 527 EGLint attr, val, i; 528 529 _eglInitConfig(conf, disp, EGL_DONT_CARE); 530 531 /* reset to default values */ 532 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 533 attr = _eglValidationTable[i].attr; 534 val = _eglValidationTable[i].default_value; 535 _eglSetConfigKey(conf, attr, val); 536 } 537 538 /* parse the list */ 539 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 540 attr = attrib_list[i]; 541 val = attrib_list[i + 1]; 542 543 if (!_eglIsConfigAttribValid(conf, attr)) 544 return EGL_FALSE; 545 546 _eglSetConfigKey(conf, attr, val); 547 } 548 549 if (!_eglValidateConfig(conf, EGL_TRUE)) 550 return EGL_FALSE; 551 552 /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */ 553 if (conf->Level == EGL_DONT_CARE || 554 conf->MatchNativePixmap == EGL_DONT_CARE) 555 return EGL_FALSE; 556 557 /* ignore other attributes when EGL_CONFIG_ID is given */ 558 if (conf->ConfigID != EGL_DONT_CARE) { 559 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 560 attr = _eglValidationTable[i].attr; 561 if (attr != EGL_CONFIG_ID) 562 _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 563 } 564 } 565 else { 566 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 567 conf->NativeVisualType = EGL_DONT_CARE; 568 569 if (conf->TransparentType == EGL_NONE) { 570 conf->TransparentRedValue = EGL_DONT_CARE; 571 conf->TransparentGreenValue = EGL_DONT_CARE; 572 conf->TransparentBlueValue = EGL_DONT_CARE; 573 } 574 } 575 576 return EGL_TRUE; 577} 578 579 580/** 581 * Decide the ordering of conf1 and conf2, under the given criteria. 582 * When compare_id is true, this implements the algorithm described 583 * in "Sorting of EGLConfigs". When compare_id is false, 584 * EGL_CONFIG_ID is not compared. 585 * 586 * It returns a negative integer if conf1 is considered to come 587 * before conf2; a positive integer if conf2 is considered to come 588 * before conf1; zero if the ordering cannot be decided. 589 * 590 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 591 * ignored here. 592 */ 593EGLint 594_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 595 const _EGLConfig *criteria, EGLBoolean compare_id) 596{ 597 const EGLint compare_attribs[] = { 598 EGL_BUFFER_SIZE, 599 EGL_SAMPLE_BUFFERS, 600 EGL_SAMPLES, 601 EGL_DEPTH_SIZE, 602 EGL_STENCIL_SIZE, 603 EGL_ALPHA_MASK_SIZE, 604 }; 605 EGLint val1, val2; 606 EGLint i; 607 608 if (conf1 == conf2) 609 return 0; 610 611 /* the enum values have the desired ordering */ 612 STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG); 613 STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 614 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 615 if (val1) 616 return val1; 617 618 /* the enum values have the desired ordering */ 619 STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 620 val1 = conf1->ColorBufferType - conf2->ColorBufferType; 621 if (val1) 622 return val1; 623 624 if (criteria) { 625 val1 = val2 = 0; 626 if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 627 if (criteria->RedSize > 0) { 628 val1 += conf1->RedSize; 629 val2 += conf2->RedSize; 630 } 631 if (criteria->GreenSize > 0) { 632 val1 += conf1->GreenSize; 633 val2 += conf2->GreenSize; 634 } 635 if (criteria->BlueSize > 0) { 636 val1 += conf1->BlueSize; 637 val2 += conf2->BlueSize; 638 } 639 } 640 else { 641 if (criteria->LuminanceSize > 0) { 642 val1 += conf1->LuminanceSize; 643 val2 += conf2->LuminanceSize; 644 } 645 } 646 if (criteria->AlphaSize > 0) { 647 val1 += conf1->AlphaSize; 648 val2 += conf2->AlphaSize; 649 } 650 } 651 else { 652 /* assume the default criteria, which gives no specific ordering */ 653 val1 = val2 = 0; 654 } 655 656 /* for color bits, larger one is preferred */ 657 if (val1 != val2) 658 return (val2 - val1); 659 660 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 661 val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 662 val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 663 if (val1 != val2) 664 return (val1 - val2); 665 } 666 667 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 668 669 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 670} 671 672 673static inline 674void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 675{ 676 const _EGLConfig *tmp = *conf1; 677 *conf1 = *conf2; 678 *conf2 = tmp; 679} 680 681 682/** 683 * Quick sort an array of configs. This differs from the standard 684 * qsort() in that the compare function accepts an additional 685 * argument. 686 */ 687static void 688_eglSortConfigs(const _EGLConfig **configs, EGLint count, 689 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 690 void *), 691 void *priv_data) 692{ 693 const EGLint pivot = 0; 694 EGLint i, j; 695 696 if (count <= 1) 697 return; 698 699 _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 700 i = 1; 701 j = count - 1; 702 do { 703 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 704 i++; 705 while (compare(configs[j], configs[pivot], priv_data) > 0) 706 j--; 707 if (i < j) { 708 _eglSwapConfigs(&configs[i], &configs[j]); 709 i++; 710 j--; 711 } 712 else if (i == j) { 713 i++; 714 j--; 715 break; 716 } 717 } while (i <= j); 718 _eglSwapConfigs(&configs[pivot], &configs[j]); 719 720 _eglSortConfigs(configs, j, compare, priv_data); 721 _eglSortConfigs(configs + i, count - i, compare, priv_data); 722} 723 724 725/** 726 * A helper function for implementing eglChooseConfig. See _eglFilterArray and 727 * _eglSortConfigs for the meanings of match and compare. 728 */ 729EGLBoolean 730_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, 731 EGLint config_size, EGLint *num_configs, 732 EGLBoolean (*match)(const _EGLConfig *, void *), 733 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 734 void *), 735 void *priv_data) 736{ 737 _EGLConfig **configList; 738 EGLint i, count; 739 740 /* get the number of matched configs */ 741 count = _eglFilterArray(array, NULL, 0, 742 (_EGLArrayForEach) match, priv_data); 743 if (!count) { 744 *num_configs = count; 745 return EGL_TRUE; 746 } 747 748 configList = malloc(sizeof(*configList) * count); 749 if (!configList) 750 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 751 752 /* get the matched configs */ 753 _eglFilterArray(array, (void **) configList, count, 754 (_EGLArrayForEach) match, priv_data); 755 756 /* perform sorting of configs */ 757 if (configs && count) { 758 _eglSortConfigs((const _EGLConfig **) configList, count, 759 compare, priv_data); 760 count = MIN2(count, config_size); 761 for (i = 0; i < count; i++) 762 configs[i] = _eglGetConfigHandle(configList[i]); 763 } 764 765 free(configList); 766 767 *num_configs = count; 768 769 return EGL_TRUE; 770} 771 772 773static EGLBoolean 774_eglFallbackMatch(const _EGLConfig *conf, void *priv_data) 775{ 776 return _eglMatchConfig(conf, (const _EGLConfig *) priv_data); 777} 778 779 780static EGLint 781_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, 782 void *priv_data) 783{ 784 return _eglCompareConfigs(conf1, conf2, 785 (const _EGLConfig *) priv_data, EGL_TRUE); 786} 787 788 789/** 790 * Typical fallback routine for eglChooseConfig 791 */ 792EGLBoolean 793_eglChooseConfig(_EGLDisplay *disp, const EGLint *attrib_list, 794 EGLConfig *configs, EGLint config_size, EGLint *num_configs) 795{ 796 _EGLConfig criteria; 797 EGLBoolean result; 798 799 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 800 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 801 802 result = _eglFilterConfigArray(disp->Configs, 803 configs, config_size, num_configs, 804 _eglFallbackMatch, _eglFallbackCompare, 805 (void *) &criteria); 806 807 if (result && (_eglGetLogLevel() == _EGL_DEBUG)) 808 eglPrintConfigDebug(disp, configs, *num_configs, EGL_TRUE); 809 810 return result; 811} 812 813 814/** 815 * Fallback for eglGetConfigAttrib. 816 */ 817EGLBoolean 818_eglGetConfigAttrib(_EGLDisplay *disp, _EGLConfig *conf, 819 EGLint attribute, EGLint *value) 820{ 821 if (!_eglIsConfigAttribValid(conf, attribute)) 822 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 823 824 /* nonqueryable attributes */ 825 switch (attribute) { 826 case EGL_MATCH_NATIVE_PIXMAP: 827 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 828 break; 829 default: 830 break; 831 } 832 833 if (!value) 834 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 835 836 *value = _eglGetConfigKey(conf, attribute); 837 return EGL_TRUE; 838} 839 840 841static EGLBoolean 842_eglFlattenConfig(void *elem, void *buffer) 843{ 844 _EGLConfig *conf = (_EGLConfig *) elem; 845 EGLConfig *handle = (EGLConfig *) buffer; 846 *handle = _eglGetConfigHandle(conf); 847 return EGL_TRUE; 848} 849 850/** 851 * Fallback for eglGetConfigs. 852 */ 853EGLBoolean 854_eglGetConfigs(_EGLDisplay *disp, EGLConfig *configs, 855 EGLint config_size, EGLint *num_config) 856{ 857 *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 858 sizeof(configs[0]), config_size, _eglFlattenConfig); 859 860 if (_eglGetLogLevel() == _EGL_DEBUG) 861 eglPrintConfigDebug(disp, configs, *num_config, EGL_FALSE); 862 863 return EGL_TRUE; 864} 865