1 /************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 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 "c99_compat.h" 40 #include "util/macros.h" 41 42 #include "eglconfig.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 */ 58 void 59 _eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id) 60 { 61 memset(conf, 0, sizeof(*conf)); 62 63 conf->Display = dpy; 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 */ 81 EGLConfig 82 _eglLinkConfig(_EGLConfig *conf) 83 { 84 _EGLDisplay *dpy = conf->Display; 85 86 /* sanity check */ 87 assert(dpy); 88 assert(conf->ConfigID > 0); 89 90 if (!dpy->Configs) { 91 dpy->Configs = _eglCreateArray("Config", 16); 92 if (!dpy->Configs) 93 return (EGLConfig) NULL; 94 } 95 96 _eglAppendArray(dpy->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 *dpy) 108 { 109 _EGLConfig *conf; 110 111 if (!dpy) 112 return NULL; 113 114 conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config); 115 if (conf) 116 assert(conf->Display == dpy); 117 118 return conf; 119 } 120 121 122 enum 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 131 enum 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 */ 141 static 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 */ 272 EGLBoolean 273 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) 274 { 275 EGLint i, attr, val; 276 EGLBoolean valid = EGL_TRUE; 277 278 /* check attributes by their types */ 279 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 280 EGLint mask; 281 282 attr = _eglValidationTable[i].attr; 283 val = _eglGetConfigKey(conf, attr); 284 285 switch (_eglValidationTable[i].type) { 286 case ATTRIB_TYPE_INTEGER: 287 switch (attr) { 288 case EGL_CONFIG_ID: 289 /* config id must be positive */ 290 if (val <= 0) 291 valid = EGL_FALSE; 292 break; 293 case EGL_SAMPLE_BUFFERS: 294 /* there can be at most 1 sample buffer */ 295 if (val > 1 || val < 0) 296 valid = EGL_FALSE; 297 break; 298 default: 299 if (val < 0) 300 valid = EGL_FALSE; 301 break; 302 } 303 break; 304 case ATTRIB_TYPE_BOOLEAN: 305 if (val != EGL_TRUE && val != EGL_FALSE) 306 valid = EGL_FALSE; 307 break; 308 case ATTRIB_TYPE_ENUM: 309 switch (attr) { 310 case EGL_CONFIG_CAVEAT: 311 if (val != EGL_NONE && val != EGL_SLOW_CONFIG && 312 val != EGL_NON_CONFORMANT_CONFIG) 313 valid = EGL_FALSE; 314 break; 315 case EGL_TRANSPARENT_TYPE: 316 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB) 317 valid = EGL_FALSE; 318 break; 319 case EGL_COLOR_BUFFER_TYPE: 320 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) 321 valid = EGL_FALSE; 322 break; 323 case EGL_COLOR_COMPONENT_TYPE_EXT: 324 if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT && 325 val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) 326 valid = EGL_FALSE; 327 break; 328 default: 329 assert(0); 330 break; 331 } 332 break; 333 case ATTRIB_TYPE_BITMASK: 334 switch (attr) { 335 case EGL_SURFACE_TYPE: 336 mask = EGL_PBUFFER_BIT | 337 EGL_PIXMAP_BIT | 338 EGL_WINDOW_BIT | 339 EGL_VG_COLORSPACE_LINEAR_BIT | 340 EGL_VG_ALPHA_FORMAT_PRE_BIT | 341 EGL_MULTISAMPLE_RESOLVE_BOX_BIT | 342 EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 343 break; 344 case EGL_RENDERABLE_TYPE: 345 case EGL_CONFORMANT: 346 mask = EGL_OPENGL_ES_BIT | 347 EGL_OPENVG_BIT | 348 EGL_OPENGL_ES2_BIT | 349 EGL_OPENGL_ES3_BIT_KHR | 350 EGL_OPENGL_BIT; 351 break; 352 default: 353 assert(0); 354 mask = 0; 355 break; 356 } 357 if (val & ~mask) 358 valid = EGL_FALSE; 359 break; 360 case ATTRIB_TYPE_PLATFORM: 361 /* unable to check platform-dependent attributes here */ 362 break; 363 case ATTRIB_TYPE_PSEUDO: 364 /* pseudo attributes should not be set */ 365 if (val != 0) 366 valid = EGL_FALSE; 367 break; 368 } 369 370 if (!valid && for_matching) { 371 /* accept EGL_DONT_CARE as a valid value */ 372 if (val == EGL_DONT_CARE) 373 valid = EGL_TRUE; 374 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 375 valid = EGL_TRUE; 376 } 377 if (!valid) { 378 _eglLog(_EGL_DEBUG, 379 "attribute 0x%04x has an invalid value 0x%x", attr, val); 380 break; 381 } 382 } 383 384 /* any invalid attribute value should have been catched */ 385 if (!valid || for_matching) 386 return valid; 387 388 /* now check for conflicting attribute values */ 389 390 switch (conf->ColorBufferType) { 391 case EGL_RGB_BUFFER: 392 if (conf->LuminanceSize) 393 valid = EGL_FALSE; 394 if (conf->RedSize + conf->GreenSize + 395 conf->BlueSize + conf->AlphaSize != conf->BufferSize) 396 valid = EGL_FALSE; 397 break; 398 case EGL_LUMINANCE_BUFFER: 399 if (conf->RedSize || conf->GreenSize || conf->BlueSize) 400 valid = EGL_FALSE; 401 if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 402 valid = EGL_FALSE; 403 break; 404 } 405 if (!valid) { 406 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 407 return EGL_FALSE; 408 } 409 410 if (!conf->SampleBuffers && conf->Samples) 411 valid = EGL_FALSE; 412 if (!valid) { 413 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 414 return EGL_FALSE; 415 } 416 417 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 418 if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 419 valid = EGL_FALSE; 420 } 421 if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 422 if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 423 valid = EGL_FALSE; 424 } 425 if (!valid) { 426 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 427 return EGL_FALSE; 428 } 429 430 return valid; 431 } 432 433 434 /** 435 * Return true if a config matches the criteria. This and 436 * _eglParseConfigAttribList together implement the algorithm 437 * described in "Selection of EGLConfigs". 438 * 439 * Note that attributes that are special (currently, only 440 * EGL_MATCH_NATIVE_PIXMAP) are ignored. 441 */ 442 EGLBoolean 443 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 444 { 445 EGLint attr, val, i; 446 EGLBoolean matched = EGL_TRUE; 447 448 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 449 EGLint cmp; 450 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 451 continue; 452 453 attr = _eglValidationTable[i].attr; 454 cmp = _eglGetConfigKey(criteria, attr); 455 if (cmp == EGL_DONT_CARE) 456 continue; 457 458 val = _eglGetConfigKey(conf, attr); 459 switch (_eglValidationTable[i].criterion) { 460 case ATTRIB_CRITERION_EXACT: 461 if (val != cmp) 462 matched = EGL_FALSE; 463 break; 464 case ATTRIB_CRITERION_ATLEAST: 465 if (val < cmp) 466 matched = EGL_FALSE; 467 break; 468 case ATTRIB_CRITERION_MASK: 469 if ((val & cmp) != cmp) 470 matched = EGL_FALSE; 471 break; 472 case ATTRIB_CRITERION_SPECIAL: 473 /* ignored here */ 474 break; 475 case ATTRIB_CRITERION_IGNORE: 476 unreachable("already handled above"); 477 break; 478 } 479 480 if (!matched) { 481 #ifndef DEBUG 482 /* only print the common errors when DEBUG is not defined */ 483 if (attr != EGL_RENDERABLE_TYPE) 484 break; 485 #endif 486 _eglLog(_EGL_DEBUG, 487 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 488 val, attr, cmp); 489 break; 490 } 491 } 492 493 return matched; 494 } 495 496 static inline EGLBoolean 497 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 498 { 499 if (_eglOffsetOfConfig(attr) < 0) 500 return EGL_FALSE; 501 502 switch (attr) { 503 case EGL_Y_INVERTED_NOK: 504 return conf->Display->Extensions.NOK_texture_from_pixmap; 505 case EGL_FRAMEBUFFER_TARGET_ANDROID: 506 return conf->Display->Extensions.ANDROID_framebuffer_target; 507 case EGL_RECORDABLE_ANDROID: 508 return conf->Display->Extensions.ANDROID_recordable; 509 default: 510 break; 511 } 512 513 return EGL_TRUE; 514 } 515 516 /** 517 * Initialize a criteria config from the given attribute list. 518 * Return EGL_FALSE if any of the attribute is invalid. 519 */ 520 EGLBoolean 521 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy, 522 const EGLint *attrib_list) 523 { 524 EGLint attr, val, i; 525 526 _eglInitConfig(conf, dpy, EGL_DONT_CARE); 527 528 /* reset to default values */ 529 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 530 attr = _eglValidationTable[i].attr; 531 val = _eglValidationTable[i].default_value; 532 _eglSetConfigKey(conf, attr, val); 533 } 534 535 /* parse the list */ 536 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 537 attr = attrib_list[i]; 538 val = attrib_list[i + 1]; 539 540 if (!_eglIsConfigAttribValid(conf, attr)) 541 return EGL_FALSE; 542 543 _eglSetConfigKey(conf, attr, val); 544 } 545 546 if (!_eglValidateConfig(conf, EGL_TRUE)) 547 return EGL_FALSE; 548 549 /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */ 550 if (conf->Level == EGL_DONT_CARE || 551 conf->MatchNativePixmap == EGL_DONT_CARE) 552 return EGL_FALSE; 553 554 /* ignore other attributes when EGL_CONFIG_ID is given */ 555 if (conf->ConfigID != EGL_DONT_CARE) { 556 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 557 attr = _eglValidationTable[i].attr; 558 if (attr != EGL_CONFIG_ID) 559 _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 560 } 561 } 562 else { 563 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 564 conf->NativeVisualType = EGL_DONT_CARE; 565 566 if (conf->TransparentType == EGL_NONE) { 567 conf->TransparentRedValue = EGL_DONT_CARE; 568 conf->TransparentGreenValue = EGL_DONT_CARE; 569 conf->TransparentBlueValue = EGL_DONT_CARE; 570 } 571 } 572 573 return EGL_TRUE; 574 } 575 576 577 /** 578 * Decide the ordering of conf1 and conf2, under the given criteria. 579 * When compare_id is true, this implements the algorithm described 580 * in "Sorting of EGLConfigs". When compare_id is false, 581 * EGL_CONFIG_ID is not compared. 582 * 583 * It returns a negative integer if conf1 is considered to come 584 * before conf2; a positive integer if conf2 is considered to come 585 * before conf1; zero if the ordering cannot be decided. 586 * 587 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 588 * ignored here. 589 */ 590 EGLint 591 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 592 const _EGLConfig *criteria, EGLBoolean compare_id) 593 { 594 const EGLint compare_attribs[] = { 595 EGL_BUFFER_SIZE, 596 EGL_SAMPLE_BUFFERS, 597 EGL_SAMPLES, 598 EGL_DEPTH_SIZE, 599 EGL_STENCIL_SIZE, 600 EGL_ALPHA_MASK_SIZE, 601 }; 602 EGLint val1, val2; 603 EGLint i; 604 605 if (conf1 == conf2) 606 return 0; 607 608 /* the enum values have the desired ordering */ 609 STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG); 610 STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 611 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 612 if (val1) 613 return val1; 614 615 /* the enum values have the desired ordering */ 616 STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 617 val1 = conf1->ColorBufferType - conf2->ColorBufferType; 618 if (val1) 619 return val1; 620 621 if (criteria) { 622 val1 = val2 = 0; 623 if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 624 if (criteria->RedSize > 0) { 625 val1 += conf1->RedSize; 626 val2 += conf2->RedSize; 627 } 628 if (criteria->GreenSize > 0) { 629 val1 += conf1->GreenSize; 630 val2 += conf2->GreenSize; 631 } 632 if (criteria->BlueSize > 0) { 633 val1 += conf1->BlueSize; 634 val2 += conf2->BlueSize; 635 } 636 } 637 else { 638 if (criteria->LuminanceSize > 0) { 639 val1 += conf1->LuminanceSize; 640 val2 += conf2->LuminanceSize; 641 } 642 } 643 if (criteria->AlphaSize > 0) { 644 val1 += conf1->AlphaSize; 645 val2 += conf2->AlphaSize; 646 } 647 } 648 else { 649 /* assume the default criteria, which gives no specific ordering */ 650 val1 = val2 = 0; 651 } 652 653 /* for color bits, larger one is preferred */ 654 if (val1 != val2) 655 return (val2 - val1); 656 657 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 658 val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 659 val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 660 if (val1 != val2) 661 return (val1 - val2); 662 } 663 664 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 665 666 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 667 } 668 669 670 static inline 671 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 672 { 673 const _EGLConfig *tmp = *conf1; 674 *conf1 = *conf2; 675 *conf2 = tmp; 676 } 677 678 679 /** 680 * Quick sort an array of configs. This differs from the standard 681 * qsort() in that the compare function accepts an additional 682 * argument. 683 */ 684 static void 685 _eglSortConfigs(const _EGLConfig **configs, EGLint count, 686 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 687 void *), 688 void *priv_data) 689 { 690 const EGLint pivot = 0; 691 EGLint i, j; 692 693 if (count <= 1) 694 return; 695 696 _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 697 i = 1; 698 j = count - 1; 699 do { 700 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 701 i++; 702 while (compare(configs[j], configs[pivot], priv_data) > 0) 703 j--; 704 if (i < j) { 705 _eglSwapConfigs(&configs[i], &configs[j]); 706 i++; 707 j--; 708 } 709 else if (i == j) { 710 i++; 711 j--; 712 break; 713 } 714 } while (i <= j); 715 _eglSwapConfigs(&configs[pivot], &configs[j]); 716 717 _eglSortConfigs(configs, j, compare, priv_data); 718 _eglSortConfigs(configs + i, count - i, compare, priv_data); 719 } 720 721 722 /** 723 * A helper function for implementing eglChooseConfig. See _eglFilterArray and 724 * _eglSortConfigs for the meanings of match and compare. 725 */ 726 EGLBoolean 727 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, 728 EGLint config_size, EGLint *num_configs, 729 EGLBoolean (*match)(const _EGLConfig *, void *), 730 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 731 void *), 732 void *priv_data) 733 { 734 _EGLConfig **configList; 735 EGLint i, count; 736 737 if (!num_configs) 738 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfig"); 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 773 static EGLBoolean 774 _eglFallbackMatch(const _EGLConfig *conf, void *priv_data) 775 { 776 return _eglMatchConfig(conf, (const _EGLConfig *) priv_data); 777 } 778 779 780 static 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 */ 792 EGLBoolean 793 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, 794 EGLConfig *configs, EGLint config_size, EGLint *num_configs) 795 { 796 _EGLConfig criteria; 797 798 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 799 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 800 801 return _eglFilterConfigArray(disp->Configs, 802 configs, config_size, num_configs, 803 _eglFallbackMatch, _eglFallbackCompare, 804 (void *) &criteria); 805 } 806 807 808 /** 809 * Fallback for eglGetConfigAttrib. 810 */ 811 EGLBoolean 812 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 813 EGLint attribute, EGLint *value) 814 { 815 if (!_eglIsConfigAttribValid(conf, attribute)) 816 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 817 818 /* nonqueryable attributes */ 819 switch (attribute) { 820 case EGL_MATCH_NATIVE_PIXMAP: 821 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 822 break; 823 default: 824 break; 825 } 826 827 if (!value) 828 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 829 830 *value = _eglGetConfigKey(conf, attribute); 831 return EGL_TRUE; 832 } 833 834 835 static EGLBoolean 836 _eglFlattenConfig(void *elem, void *buffer) 837 { 838 _EGLConfig *conf = (_EGLConfig *) elem; 839 EGLConfig *handle = (EGLConfig *) buffer; 840 *handle = _eglGetConfigHandle(conf); 841 return EGL_TRUE; 842 } 843 844 /** 845 * Fallback for eglGetConfigs. 846 */ 847 EGLBoolean 848 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, 849 EGLint config_size, EGLint *num_config) 850 { 851 if (!num_config) 852 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); 853 854 *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 855 sizeof(configs[0]), config_size, _eglFlattenConfig); 856 857 return EGL_TRUE; 858 } 859