egl: combine VersionMajor and VersionMinor into one variable
[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 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 break;
327 case EGL_RENDERABLE_TYPE:
328 case EGL_CONFORMANT:
329 mask = EGL_OPENGL_ES_BIT |
330 EGL_OPENVG_BIT |
331 EGL_OPENGL_ES2_BIT |
332 EGL_OPENGL_ES3_BIT_KHR |
333 EGL_OPENGL_BIT;
334 break;
335 default:
336 assert(0);
337 mask = 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 */
428 EGLBoolean
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
482 static 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 */
502 EGLBoolean
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 /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
532 if (conf->Level == EGL_DONT_CARE ||
533 conf->MatchNativePixmap == EGL_DONT_CARE)
534 return EGL_FALSE;
535
536 /* ignore other attributes when EGL_CONFIG_ID is given */
537 if (conf->ConfigID != EGL_DONT_CARE) {
538 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
539 attr = _eglValidationTable[i].attr;
540 if (attr != EGL_CONFIG_ID)
541 _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
542 }
543 }
544 else {
545 if (!(conf->SurfaceType & EGL_WINDOW_BIT))
546 conf->NativeVisualType = EGL_DONT_CARE;
547
548 if (conf->TransparentType == EGL_NONE) {
549 conf->TransparentRedValue = EGL_DONT_CARE;
550 conf->TransparentGreenValue = EGL_DONT_CARE;
551 conf->TransparentBlueValue = EGL_DONT_CARE;
552 }
553 }
554
555 return EGL_TRUE;
556 }
557
558
559 /**
560 * Decide the ordering of conf1 and conf2, under the given criteria.
561 * When compare_id is true, this implements the algorithm described
562 * in "Sorting of EGLConfigs". When compare_id is false,
563 * EGL_CONFIG_ID is not compared.
564 *
565 * It returns a negative integer if conf1 is considered to come
566 * before conf2; a positive integer if conf2 is considered to come
567 * before conf1; zero if the ordering cannot be decided.
568 *
569 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
570 * ignored here.
571 */
572 EGLint
573 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
574 const _EGLConfig *criteria, EGLBoolean compare_id)
575 {
576 const EGLint compare_attribs[] = {
577 EGL_BUFFER_SIZE,
578 EGL_SAMPLE_BUFFERS,
579 EGL_SAMPLES,
580 EGL_DEPTH_SIZE,
581 EGL_STENCIL_SIZE,
582 EGL_ALPHA_MASK_SIZE,
583 };
584 EGLint val1, val2;
585 EGLint i;
586
587 if (conf1 == conf2)
588 return 0;
589
590 /* the enum values have the desired ordering */
591 assert(EGL_NONE < EGL_SLOW_CONFIG);
592 assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
593 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
594 if (val1)
595 return val1;
596
597 /* the enum values have the desired ordering */
598 assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
599 val1 = conf1->ColorBufferType - conf2->ColorBufferType;
600 if (val1)
601 return val1;
602
603 if (criteria) {
604 val1 = val2 = 0;
605 if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
606 if (criteria->RedSize > 0) {
607 val1 += conf1->RedSize;
608 val2 += conf2->RedSize;
609 }
610 if (criteria->GreenSize > 0) {
611 val1 += conf1->GreenSize;
612 val2 += conf2->GreenSize;
613 }
614 if (criteria->BlueSize > 0) {
615 val1 += conf1->BlueSize;
616 val2 += conf2->BlueSize;
617 }
618 }
619 else {
620 if (criteria->LuminanceSize > 0) {
621 val1 += conf1->LuminanceSize;
622 val2 += conf2->LuminanceSize;
623 }
624 }
625 if (criteria->AlphaSize > 0) {
626 val1 += conf1->AlphaSize;
627 val2 += conf2->AlphaSize;
628 }
629 }
630 else {
631 /* assume the default criteria, which gives no specific ordering */
632 val1 = val2 = 0;
633 }
634
635 /* for color bits, larger one is preferred */
636 if (val1 != val2)
637 return (val2 - val1);
638
639 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
640 val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
641 val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
642 if (val1 != val2)
643 return (val1 - val2);
644 }
645
646 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
647
648 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
649 }
650
651
652 static inline
653 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
654 {
655 const _EGLConfig *tmp = *conf1;
656 *conf1 = *conf2;
657 *conf2 = tmp;
658 }
659
660
661 /**
662 * Quick sort an array of configs. This differs from the standard
663 * qsort() in that the compare function accepts an additional
664 * argument.
665 */
666 static void
667 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
668 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
669 void *),
670 void *priv_data)
671 {
672 const EGLint pivot = 0;
673 EGLint i, j;
674
675 if (count <= 1)
676 return;
677
678 _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
679 i = 1;
680 j = count - 1;
681 do {
682 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
683 i++;
684 while (compare(configs[j], configs[pivot], priv_data) > 0)
685 j--;
686 if (i < j) {
687 _eglSwapConfigs(&configs[i], &configs[j]);
688 i++;
689 j--;
690 }
691 else if (i == j) {
692 i++;
693 j--;
694 break;
695 }
696 } while (i <= j);
697 _eglSwapConfigs(&configs[pivot], &configs[j]);
698
699 _eglSortConfigs(configs, j, compare, priv_data);
700 _eglSortConfigs(configs + i, count - i, compare, priv_data);
701 }
702
703
704 /**
705 * A helper function for implementing eglChooseConfig. See _eglFilterArray and
706 * _eglSortConfigs for the meanings of match and compare.
707 */
708 EGLBoolean
709 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
710 EGLint config_size, EGLint *num_configs,
711 EGLBoolean (*match)(const _EGLConfig *, void *),
712 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
713 void *),
714 void *priv_data)
715 {
716 _EGLConfig **configList;
717 EGLint i, count;
718
719 if (!num_configs)
720 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
721
722 /* get the number of matched configs */
723 count = _eglFilterArray(array, NULL, 0,
724 (_EGLArrayForEach) match, priv_data);
725 if (!count) {
726 *num_configs = count;
727 return EGL_TRUE;
728 }
729
730 configList = malloc(sizeof(*configList) * count);
731 if (!configList)
732 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
733
734 /* get the matched configs */
735 _eglFilterArray(array, (void **) configList, count,
736 (_EGLArrayForEach) match, priv_data);
737
738 /* perform sorting of configs */
739 if (configs && count) {
740 _eglSortConfigs((const _EGLConfig **) configList, count,
741 compare, priv_data);
742 count = MIN2(count, config_size);
743 for (i = 0; i < count; i++)
744 configs[i] = _eglGetConfigHandle(configList[i]);
745 }
746
747 free(configList);
748
749 *num_configs = count;
750
751 return EGL_TRUE;
752 }
753
754
755 static EGLBoolean
756 _eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
757 {
758 return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
759 }
760
761
762 static EGLint
763 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
764 void *priv_data)
765 {
766 return _eglCompareConfigs(conf1, conf2,
767 (const _EGLConfig *) priv_data, EGL_TRUE);
768 }
769
770
771 /**
772 * Typical fallback routine for eglChooseConfig
773 */
774 EGLBoolean
775 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
776 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
777 {
778 _EGLConfig criteria;
779
780 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
781 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
782
783 return _eglFilterConfigArray(disp->Configs,
784 configs, config_size, num_configs,
785 _eglFallbackMatch, _eglFallbackCompare,
786 (void *) &criteria);
787 }
788
789
790 /**
791 * Fallback for eglGetConfigAttrib.
792 */
793 EGLBoolean
794 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
795 EGLint attribute, EGLint *value)
796 {
797 if (!_eglIsConfigAttribValid(conf, attribute))
798 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
799
800 /* nonqueryable attributes */
801 switch (attribute) {
802 case EGL_MATCH_NATIVE_PIXMAP:
803 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
804 break;
805 default:
806 break;
807 }
808
809 if (!value)
810 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
811
812 *value = _eglGetConfigKey(conf, attribute);
813 return EGL_TRUE;
814 }
815
816
817 static EGLBoolean
818 _eglFlattenConfig(void *elem, void *buffer)
819 {
820 _EGLConfig *conf = (_EGLConfig *) elem;
821 EGLConfig *handle = (EGLConfig *) buffer;
822 *handle = _eglGetConfigHandle(conf);
823 return EGL_TRUE;
824 }
825
826 /**
827 * Fallback for eglGetConfigs.
828 */
829 EGLBoolean
830 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
831 EGLint config_size, EGLint *num_config)
832 {
833 if (!num_config)
834 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
835
836 *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
837 sizeof(configs[0]), config_size, _eglFlattenConfig);
838
839 return EGL_TRUE;
840 }