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