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