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