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