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