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