eglconfig.c revision 3464ebd5
1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 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 "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 */ 56void 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 */ 78PUBLIC 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 118enum { 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 */ 136static 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 */ 258EGLBoolean 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 break; 339 } 340 if (val & ~mask) 341 valid = EGL_FALSE; 342 break; 343 case ATTRIB_TYPE_PLATFORM: 344 /* unable to check platform-dependent attributes here */ 345 break; 346 case ATTRIB_TYPE_PSEUDO: 347 /* pseudo attributes should not be set */ 348 if (val != 0) 349 valid = EGL_FALSE; 350 break; 351 default: 352 assert(0); 353 break; 354 } 355 356 if (!valid && for_matching) { 357 /* accept EGL_DONT_CARE as a valid value */ 358 if (val == EGL_DONT_CARE) 359 valid = EGL_TRUE; 360 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL) 361 valid = EGL_TRUE; 362 } 363 if (!valid) { 364 _eglLog(_EGL_DEBUG, 365 "attribute 0x%04x has an invalid value 0x%x", attr, val); 366 break; 367 } 368 } 369 370 /* any invalid attribute value should have been catched */ 371 if (!valid || for_matching) 372 return valid; 373 374 /* now check for conflicting attribute values */ 375 376 switch (conf->ColorBufferType) { 377 case EGL_RGB_BUFFER: 378 if (conf->LuminanceSize) 379 valid = EGL_FALSE; 380 if (conf->RedSize + conf->GreenSize + 381 conf->BlueSize + conf->AlphaSize != conf->BufferSize) 382 valid = EGL_FALSE; 383 break; 384 case EGL_LUMINANCE_BUFFER: 385 if (conf->RedSize || conf->GreenSize || conf->BlueSize) 386 valid = EGL_FALSE; 387 if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) 388 valid = EGL_FALSE; 389 break; 390 } 391 if (!valid) { 392 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); 393 return EGL_FALSE; 394 } 395 396 if (!conf->SampleBuffers && conf->Samples) 397 valid = EGL_FALSE; 398 if (!valid) { 399 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers"); 400 return EGL_FALSE; 401 } 402 403 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) { 404 if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE) 405 valid = EGL_FALSE; 406 } 407 if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) { 408 if (conf->BindToTextureRGB || conf->BindToTextureRGBA) 409 valid = EGL_FALSE; 410 } 411 if (!valid) { 412 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding"); 413 return EGL_FALSE; 414 } 415 416 return valid; 417} 418 419 420/** 421 * Return true if a config matches the criteria. This and 422 * _eglParseConfigAttribList together implement the algorithm 423 * described in "Selection of EGLConfigs". 424 * 425 * Note that attributes that are special (currently, only 426 * EGL_MATCH_NATIVE_PIXMAP) are ignored. 427 */ 428EGLBoolean 429_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria) 430{ 431 EGLint attr, val, i; 432 EGLBoolean matched = EGL_TRUE; 433 434 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 435 EGLint cmp; 436 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE) 437 continue; 438 439 attr = _eglValidationTable[i].attr; 440 cmp = _eglGetConfigKey(criteria, attr); 441 if (cmp == EGL_DONT_CARE) 442 continue; 443 444 val = _eglGetConfigKey(conf, attr); 445 switch (_eglValidationTable[i].criterion) { 446 case ATTRIB_CRITERION_EXACT: 447 if (val != cmp) 448 matched = EGL_FALSE; 449 break; 450 case ATTRIB_CRITERION_ATLEAST: 451 if (val < cmp) 452 matched = EGL_FALSE; 453 break; 454 case ATTRIB_CRITERION_MASK: 455 if ((val & cmp) != cmp) 456 matched = EGL_FALSE; 457 break; 458 case ATTRIB_CRITERION_SPECIAL: 459 /* ignored here */ 460 break; 461 default: 462 assert(0); 463 break; 464 } 465 466 if (!matched) { 467#ifndef DEBUG 468 /* only print the common errors when DEBUG is not defined */ 469 if (attr != EGL_RENDERABLE_TYPE) 470 break; 471#endif 472 _eglLog(_EGL_DEBUG, 473 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)", 474 val, attr, cmp); 475 break; 476 } 477 } 478 479 return matched; 480} 481 482static INLINE EGLBoolean 483_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) 484{ 485 if (_eglOffsetOfConfig(attr) < 0) 486 return EGL_FALSE; 487 488 switch (attr) { 489 case EGL_Y_INVERTED_NOK: 490 return conf->Display->Extensions.NOK_texture_from_pixmap; 491 default: 492 break; 493 } 494 495 return EGL_TRUE; 496} 497 498/** 499 * Initialize a criteria config from the given attribute list. 500 * Return EGL_FALSE if any of the attribute is invalid. 501 */ 502EGLBoolean 503_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy, 504 const EGLint *attrib_list) 505{ 506 EGLint attr, val, i; 507 508 _eglInitConfig(conf, dpy, EGL_DONT_CARE); 509 510 /* reset to default values */ 511 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 512 attr = _eglValidationTable[i].attr; 513 val = _eglValidationTable[i].default_value; 514 _eglSetConfigKey(conf, attr, val); 515 } 516 517 /* parse the list */ 518 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) { 519 attr = attrib_list[i]; 520 val = attrib_list[i + 1]; 521 522 if (!_eglIsConfigAttribValid(conf, attr)) 523 return EGL_FALSE; 524 525 _eglSetConfigKey(conf, attr, val); 526 } 527 528 if (!_eglValidateConfig(conf, EGL_TRUE)) 529 return EGL_FALSE; 530 531 /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */ 532 if (conf->Level == EGL_DONT_CARE) 533 return EGL_FALSE; 534 535 /* ignore other attributes when EGL_CONFIG_ID is given */ 536 if (conf->ConfigID != EGL_DONT_CARE) { 537 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) { 538 attr = _eglValidationTable[i].attr; 539 if (attr != EGL_CONFIG_ID) 540 _eglSetConfigKey(conf, attr, EGL_DONT_CARE); 541 } 542 } 543 else { 544 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) 545 conf->NativeVisualType = EGL_DONT_CARE; 546 547 if (conf->TransparentType == EGL_NONE) { 548 conf->TransparentRedValue = EGL_DONT_CARE; 549 conf->TransparentGreenValue = EGL_DONT_CARE; 550 conf->TransparentBlueValue = EGL_DONT_CARE; 551 } 552 } 553 554 return EGL_TRUE; 555} 556 557 558/** 559 * Decide the ordering of conf1 and conf2, under the given criteria. 560 * When compare_id is true, this implements the algorithm described 561 * in "Sorting of EGLConfigs". When compare_id is false, 562 * EGL_CONFIG_ID is not compared. 563 * 564 * It returns a negative integer if conf1 is considered to come 565 * before conf2; a positive integer if conf2 is considered to come 566 * before conf1; zero if the ordering cannot be decided. 567 * 568 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is 569 * ignored here. 570 */ 571EGLint 572_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, 573 const _EGLConfig *criteria, EGLBoolean compare_id) 574{ 575 const EGLint compare_attribs[] = { 576 EGL_BUFFER_SIZE, 577 EGL_SAMPLE_BUFFERS, 578 EGL_SAMPLES, 579 EGL_DEPTH_SIZE, 580 EGL_STENCIL_SIZE, 581 EGL_ALPHA_MASK_SIZE, 582 }; 583 EGLint val1, val2; 584 EGLint i; 585 586 if (conf1 == conf2) 587 return 0; 588 589 /* the enum values have the desired ordering */ 590 assert(EGL_NONE < EGL_SLOW_CONFIG); 591 assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); 592 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat; 593 if (val1) 594 return val1; 595 596 /* the enum values have the desired ordering */ 597 assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); 598 val1 = conf1->ColorBufferType - conf2->ColorBufferType; 599 if (val1) 600 return val1; 601 602 if (criteria) { 603 val1 = val2 = 0; 604 if (conf1->ColorBufferType == EGL_RGB_BUFFER) { 605 if (criteria->RedSize > 0) { 606 val1 += conf1->RedSize; 607 val2 += conf2->RedSize; 608 } 609 if (criteria->GreenSize > 0) { 610 val1 += conf1->GreenSize; 611 val2 += conf2->GreenSize; 612 } 613 if (criteria->BlueSize > 0) { 614 val1 += conf1->BlueSize; 615 val2 += conf2->BlueSize; 616 } 617 } 618 else { 619 if (criteria->LuminanceSize > 0) { 620 val1 += conf1->LuminanceSize; 621 val2 += conf2->LuminanceSize; 622 } 623 } 624 if (criteria->AlphaSize > 0) { 625 val1 += conf1->AlphaSize; 626 val2 += conf2->AlphaSize; 627 } 628 } 629 else { 630 /* assume the default criteria, which gives no specific ordering */ 631 val1 = val2 = 0; 632 } 633 634 /* for color bits, larger one is preferred */ 635 if (val1 != val2) 636 return (val2 - val1); 637 638 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) { 639 val1 = _eglGetConfigKey(conf1, compare_attribs[i]); 640 val2 = _eglGetConfigKey(conf2, compare_attribs[i]); 641 if (val1 != val2) 642 return (val1 - val2); 643 } 644 645 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ 646 647 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; 648} 649 650 651static INLINE 652void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2) 653{ 654 const _EGLConfig *tmp = *conf1; 655 *conf1 = *conf2; 656 *conf2 = tmp; 657} 658 659 660/** 661 * Quick sort an array of configs. This differs from the standard 662 * qsort() in that the compare function accepts an additional 663 * argument. 664 */ 665void 666_eglSortConfigs(const _EGLConfig **configs, EGLint count, 667 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *, 668 void *), 669 void *priv_data) 670{ 671 const EGLint pivot = 0; 672 EGLint i, j; 673 674 if (count <= 1) 675 return; 676 677 _eglSwapConfigs(&configs[pivot], &configs[count / 2]); 678 i = 1; 679 j = count - 1; 680 do { 681 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0) 682 i++; 683 while (compare(configs[j], configs[pivot], priv_data) > 0) 684 j--; 685 if (i < j) { 686 _eglSwapConfigs(&configs[i], &configs[j]); 687 i++; 688 j--; 689 } 690 else if (i == j) { 691 i++; 692 j--; 693 break; 694 } 695 } while (i <= j); 696 _eglSwapConfigs(&configs[pivot], &configs[j]); 697 698 _eglSortConfigs(configs, j, compare, priv_data); 699 _eglSortConfigs(configs + i, count - i, compare, priv_data); 700} 701 702 703static int 704_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2, 705 void *priv_data) 706{ 707 const _EGLConfig *criteria = (const _EGLConfig *) priv_data; 708 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE); 709} 710 711 712/** 713 * Typical fallback routine for eglChooseConfig 714 */ 715EGLBoolean 716_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list, 717 EGLConfig *configs, EGLint config_size, EGLint *num_configs) 718{ 719 _EGLConfig **configList, criteria; 720 EGLint i, count; 721 722 if (!num_configs) 723 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs"); 724 725 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) 726 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); 727 728 /* get the number of matched configs */ 729 count = _eglFilterArray(disp->Configs, NULL, 0, 730 (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria); 731 if (!count) { 732 *num_configs = count; 733 return EGL_TRUE; 734 } 735 736 configList = malloc(sizeof(*configList) * count); 737 if (!configList) 738 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)"); 739 740 /* get the matched configs */ 741 _eglFilterArray(disp->Configs, (void **) configList, count, 742 (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria); 743 744 /* perform sorting of configs */ 745 if (configs && count) { 746 _eglSortConfigs((const _EGLConfig **) configList, count, 747 _eglFallbackCompare, (void *) &criteria); 748 count = MIN2(count, config_size); 749 for (i = 0; i < count; i++) 750 configs[i] = _eglGetConfigHandle(configList[i]); 751 } 752 753 free(configList); 754 755 *num_configs = count; 756 757 return EGL_TRUE; 758} 759 760 761/** 762 * Fallback for eglGetConfigAttrib. 763 */ 764EGLBoolean 765_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf, 766 EGLint attribute, EGLint *value) 767{ 768 if (!_eglIsConfigAttribValid(conf, attribute)) 769 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 770 771 /* nonqueryable attributes */ 772 switch (attribute) { 773 case EGL_MATCH_NATIVE_PIXMAP: 774 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib"); 775 break; 776 default: 777 break; 778 } 779 780 if (!value) 781 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib"); 782 783 *value = _eglGetConfigKey(conf, attribute); 784 return EGL_TRUE; 785} 786 787 788static EGLBoolean 789_eglFlattenConfig(void *elem, void *buffer) 790{ 791 _EGLConfig *conf = (_EGLConfig *) elem; 792 EGLConfig *handle = (EGLConfig *) buffer; 793 *handle = _eglGetConfigHandle(conf); 794 return EGL_TRUE; 795} 796 797/** 798 * Fallback for eglGetConfigs. 799 */ 800EGLBoolean 801_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs, 802 EGLint config_size, EGLint *num_config) 803{ 804 if (!num_config) 805 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs"); 806 807 *num_config = _eglFlattenArray(disp->Configs, (void *) configs, 808 sizeof(configs[0]), config_size, _eglFlattenConfig); 809 810 return EGL_TRUE; 811} 812