egl/surfaceless: Set disp->DriverData to NULL on error
[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
48
49 /**
50 * Init the given _EGLconfig to default values.
51 * \param id the configuration's ID.
52 *
53 * Note that id must be positive for the config to be valid.
54 * It is also recommended that when there are N configs, their
55 * IDs are from 1 to N respectively.
56 */
57 void
58 _eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
59 {
60 memset(conf, 0, sizeof(*conf));
61
62 conf->Display = dpy;
63
64 /* some attributes take non-zero default values */
65 conf->ConfigID = id;
66 conf->ConfigCaveat = EGL_NONE;
67 conf->TransparentType = EGL_NONE;
68 conf->NativeVisualType = EGL_NONE;
69 conf->ColorBufferType = EGL_RGB_BUFFER;
70 }
71
72
73 /**
74 * Link a config to its display and return the handle of the link.
75 * The handle can be passed to client directly.
76 *
77 * Note that we just save the ptr to the config (we don't copy the config).
78 */
79 EGLConfig
80 _eglLinkConfig(_EGLConfig *conf)
81 {
82 _EGLDisplay *dpy = conf->Display;
83
84 /* sanity check */
85 assert(dpy);
86 assert(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 { EGL_FRAMEBUFFER_TARGET_ANDROID, ATTRIB_TYPE_BOOLEAN,
250 ATTRIB_CRITERION_EXACT,
251 EGL_DONT_CARE },
252 { EGL_RECORDABLE_ANDROID, ATTRIB_TYPE_BOOLEAN,
253 ATTRIB_CRITERION_EXACT,
254 EGL_DONT_CARE },
255 };
256
257
258 /**
259 * Return true if a config is valid. When for_matching is true,
260 * EGL_DONT_CARE is accepted as a valid attribute value, and checks
261 * for conflicting attribute values are skipped.
262 *
263 * Note that some attributes are platform-dependent and are not
264 * checked.
265 */
266 EGLBoolean
267 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
268 {
269 EGLint i, attr, val;
270 EGLBoolean valid = EGL_TRUE;
271
272 /* check attributes by their types */
273 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
274 EGLint mask;
275
276 attr = _eglValidationTable[i].attr;
277 val = _eglGetConfigKey(conf, attr);
278
279 switch (_eglValidationTable[i].type) {
280 case ATTRIB_TYPE_INTEGER:
281 switch (attr) {
282 case EGL_CONFIG_ID:
283 /* config id must be positive */
284 if (val <= 0)
285 valid = EGL_FALSE;
286 break;
287 case EGL_SAMPLE_BUFFERS:
288 /* there can be at most 1 sample buffer */
289 if (val > 1 || val < 0)
290 valid = EGL_FALSE;
291 break;
292 default:
293 if (val < 0)
294 valid = EGL_FALSE;
295 break;
296 }
297 break;
298 case ATTRIB_TYPE_BOOLEAN:
299 if (val != EGL_TRUE && val != EGL_FALSE)
300 valid = EGL_FALSE;
301 break;
302 case ATTRIB_TYPE_ENUM:
303 switch (attr) {
304 case EGL_CONFIG_CAVEAT:
305 if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
306 val != EGL_NON_CONFORMANT_CONFIG)
307 valid = EGL_FALSE;
308 break;
309 case EGL_TRANSPARENT_TYPE:
310 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
311 valid = EGL_FALSE;
312 break;
313 case EGL_COLOR_BUFFER_TYPE:
314 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
315 valid = EGL_FALSE;
316 break;
317 default:
318 assert(0);
319 break;
320 }
321 break;
322 case ATTRIB_TYPE_BITMASK:
323 switch (attr) {
324 case EGL_SURFACE_TYPE:
325 mask = EGL_PBUFFER_BIT |
326 EGL_PIXMAP_BIT |
327 EGL_WINDOW_BIT |
328 EGL_VG_COLORSPACE_LINEAR_BIT |
329 EGL_VG_ALPHA_FORMAT_PRE_BIT |
330 EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
331 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
332 break;
333 case EGL_RENDERABLE_TYPE:
334 case EGL_CONFORMANT:
335 mask = EGL_OPENGL_ES_BIT |
336 EGL_OPENVG_BIT |
337 EGL_OPENGL_ES2_BIT |
338 EGL_OPENGL_ES3_BIT_KHR |
339 EGL_OPENGL_BIT;
340 break;
341 default:
342 assert(0);
343 mask = 0;
344 break;
345 }
346 if (val & ~mask)
347 valid = EGL_FALSE;
348 break;
349 case ATTRIB_TYPE_PLATFORM:
350 /* unable to check platform-dependent attributes here */
351 break;
352 case ATTRIB_TYPE_PSEUDO:
353 /* pseudo attributes should not be set */
354 if (val != 0)
355 valid = EGL_FALSE;
356 break;
357 default:
358 assert(0);
359 break;
360 }
361
362 if (!valid && for_matching) {
363 /* accept EGL_DONT_CARE as a valid value */
364 if (val == EGL_DONT_CARE)
365 valid = EGL_TRUE;
366 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
367 valid = EGL_TRUE;
368 }
369 if (!valid) {
370 _eglLog(_EGL_DEBUG,
371 "attribute 0x%04x has an invalid value 0x%x", attr, val);
372 break;
373 }
374 }
375
376 /* any invalid attribute value should have been catched */
377 if (!valid || for_matching)
378 return valid;
379
380 /* now check for conflicting attribute values */
381
382 switch (conf->ColorBufferType) {
383 case EGL_RGB_BUFFER:
384 if (conf->LuminanceSize)
385 valid = EGL_FALSE;
386 if (conf->RedSize + conf->GreenSize +
387 conf->BlueSize + conf->AlphaSize != conf->BufferSize)
388 valid = EGL_FALSE;
389 break;
390 case EGL_LUMINANCE_BUFFER:
391 if (conf->RedSize || conf->GreenSize || conf->BlueSize)
392 valid = EGL_FALSE;
393 if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
394 valid = EGL_FALSE;
395 break;
396 }
397 if (!valid) {
398 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
399 return EGL_FALSE;
400 }
401
402 if (!conf->SampleBuffers && conf->Samples)
403 valid = EGL_FALSE;
404 if (!valid) {
405 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
406 return EGL_FALSE;
407 }
408
409 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
410 if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
411 valid = EGL_FALSE;
412 }
413 if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
414 if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
415 valid = EGL_FALSE;
416 }
417 if (!valid) {
418 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
419 return EGL_FALSE;
420 }
421
422 return valid;
423 }
424
425
426 /**
427 * Return true if a config matches the criteria. This and
428 * _eglParseConfigAttribList together implement the algorithm
429 * described in "Selection of EGLConfigs".
430 *
431 * Note that attributes that are special (currently, only
432 * EGL_MATCH_NATIVE_PIXMAP) are ignored.
433 */
434 EGLBoolean
435 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
436 {
437 EGLint attr, val, i;
438 EGLBoolean matched = EGL_TRUE;
439
440 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
441 EGLint cmp;
442 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
443 continue;
444
445 attr = _eglValidationTable[i].attr;
446 cmp = _eglGetConfigKey(criteria, attr);
447 if (cmp == EGL_DONT_CARE)
448 continue;
449
450 val = _eglGetConfigKey(conf, attr);
451 switch (_eglValidationTable[i].criterion) {
452 case ATTRIB_CRITERION_EXACT:
453 if (val != cmp)
454 matched = EGL_FALSE;
455 break;
456 case ATTRIB_CRITERION_ATLEAST:
457 if (val < cmp)
458 matched = EGL_FALSE;
459 break;
460 case ATTRIB_CRITERION_MASK:
461 if ((val & cmp) != cmp)
462 matched = EGL_FALSE;
463 break;
464 case ATTRIB_CRITERION_SPECIAL:
465 /* ignored here */
466 break;
467 default:
468 assert(0);
469 break;
470 }
471
472 if (!matched) {
473 #ifndef DEBUG
474 /* only print the common errors when DEBUG is not defined */
475 if (attr != EGL_RENDERABLE_TYPE)
476 break;
477 #endif
478 _eglLog(_EGL_DEBUG,
479 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
480 val, attr, cmp);
481 break;
482 }
483 }
484
485 return matched;
486 }
487
488 static inline EGLBoolean
489 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
490 {
491 if (_eglOffsetOfConfig(attr) < 0)
492 return EGL_FALSE;
493
494 switch (attr) {
495 case EGL_Y_INVERTED_NOK:
496 return conf->Display->Extensions.NOK_texture_from_pixmap;
497 case EGL_FRAMEBUFFER_TARGET_ANDROID:
498 return conf->Display->Extensions.ANDROID_framebuffer_target;
499 case EGL_RECORDABLE_ANDROID:
500 return conf->Display->Extensions.ANDROID_recordable;
501 default:
502 break;
503 }
504
505 return EGL_TRUE;
506 }
507
508 /**
509 * Initialize a criteria config from the given attribute list.
510 * Return EGL_FALSE if any of the attribute is invalid.
511 */
512 EGLBoolean
513 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
514 const EGLint *attrib_list)
515 {
516 EGLint attr, val, i;
517
518 _eglInitConfig(conf, dpy, EGL_DONT_CARE);
519
520 /* reset to default values */
521 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
522 attr = _eglValidationTable[i].attr;
523 val = _eglValidationTable[i].default_value;
524 _eglSetConfigKey(conf, attr, val);
525 }
526
527 /* parse the list */
528 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
529 attr = attrib_list[i];
530 val = attrib_list[i + 1];
531
532 if (!_eglIsConfigAttribValid(conf, attr))
533 return EGL_FALSE;
534
535 _eglSetConfigKey(conf, attr, val);
536 }
537
538 if (!_eglValidateConfig(conf, EGL_TRUE))
539 return EGL_FALSE;
540
541 /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
542 if (conf->Level == EGL_DONT_CARE ||
543 conf->MatchNativePixmap == EGL_DONT_CARE)
544 return EGL_FALSE;
545
546 /* ignore other attributes when EGL_CONFIG_ID is given */
547 if (conf->ConfigID != EGL_DONT_CARE) {
548 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
549 attr = _eglValidationTable[i].attr;
550 if (attr != EGL_CONFIG_ID)
551 _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
552 }
553 }
554 else {
555 if (!(conf->SurfaceType & EGL_WINDOW_BIT))
556 conf->NativeVisualType = EGL_DONT_CARE;
557
558 if (conf->TransparentType == EGL_NONE) {
559 conf->TransparentRedValue = EGL_DONT_CARE;
560 conf->TransparentGreenValue = EGL_DONT_CARE;
561 conf->TransparentBlueValue = EGL_DONT_CARE;
562 }
563 }
564
565 return EGL_TRUE;
566 }
567
568
569 /**
570 * Decide the ordering of conf1 and conf2, under the given criteria.
571 * When compare_id is true, this implements the algorithm described
572 * in "Sorting of EGLConfigs". When compare_id is false,
573 * EGL_CONFIG_ID is not compared.
574 *
575 * It returns a negative integer if conf1 is considered to come
576 * before conf2; a positive integer if conf2 is considered to come
577 * before conf1; zero if the ordering cannot be decided.
578 *
579 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
580 * ignored here.
581 */
582 EGLint
583 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
584 const _EGLConfig *criteria, EGLBoolean compare_id)
585 {
586 const EGLint compare_attribs[] = {
587 EGL_BUFFER_SIZE,
588 EGL_SAMPLE_BUFFERS,
589 EGL_SAMPLES,
590 EGL_DEPTH_SIZE,
591 EGL_STENCIL_SIZE,
592 EGL_ALPHA_MASK_SIZE,
593 };
594 EGLint val1, val2;
595 EGLint i;
596
597 if (conf1 == conf2)
598 return 0;
599
600 /* the enum values have the desired ordering */
601 assert(EGL_NONE < EGL_SLOW_CONFIG);
602 assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
603 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
604 if (val1)
605 return val1;
606
607 /* the enum values have the desired ordering */
608 assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
609 val1 = conf1->ColorBufferType - conf2->ColorBufferType;
610 if (val1)
611 return val1;
612
613 if (criteria) {
614 val1 = val2 = 0;
615 if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
616 if (criteria->RedSize > 0) {
617 val1 += conf1->RedSize;
618 val2 += conf2->RedSize;
619 }
620 if (criteria->GreenSize > 0) {
621 val1 += conf1->GreenSize;
622 val2 += conf2->GreenSize;
623 }
624 if (criteria->BlueSize > 0) {
625 val1 += conf1->BlueSize;
626 val2 += conf2->BlueSize;
627 }
628 }
629 else {
630 if (criteria->LuminanceSize > 0) {
631 val1 += conf1->LuminanceSize;
632 val2 += conf2->LuminanceSize;
633 }
634 }
635 if (criteria->AlphaSize > 0) {
636 val1 += conf1->AlphaSize;
637 val2 += conf2->AlphaSize;
638 }
639 }
640 else {
641 /* assume the default criteria, which gives no specific ordering */
642 val1 = val2 = 0;
643 }
644
645 /* for color bits, larger one is preferred */
646 if (val1 != val2)
647 return (val2 - val1);
648
649 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
650 val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
651 val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
652 if (val1 != val2)
653 return (val1 - val2);
654 }
655
656 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
657
658 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
659 }
660
661
662 static inline
663 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
664 {
665 const _EGLConfig *tmp = *conf1;
666 *conf1 = *conf2;
667 *conf2 = tmp;
668 }
669
670
671 /**
672 * Quick sort an array of configs. This differs from the standard
673 * qsort() in that the compare function accepts an additional
674 * argument.
675 */
676 static void
677 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
678 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
679 void *),
680 void *priv_data)
681 {
682 const EGLint pivot = 0;
683 EGLint i, j;
684
685 if (count <= 1)
686 return;
687
688 _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
689 i = 1;
690 j = count - 1;
691 do {
692 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
693 i++;
694 while (compare(configs[j], configs[pivot], priv_data) > 0)
695 j--;
696 if (i < j) {
697 _eglSwapConfigs(&configs[i], &configs[j]);
698 i++;
699 j--;
700 }
701 else if (i == j) {
702 i++;
703 j--;
704 break;
705 }
706 } while (i <= j);
707 _eglSwapConfigs(&configs[pivot], &configs[j]);
708
709 _eglSortConfigs(configs, j, compare, priv_data);
710 _eglSortConfigs(configs + i, count - i, compare, priv_data);
711 }
712
713
714 /**
715 * A helper function for implementing eglChooseConfig. See _eglFilterArray and
716 * _eglSortConfigs for the meanings of match and compare.
717 */
718 EGLBoolean
719 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
720 EGLint config_size, EGLint *num_configs,
721 EGLBoolean (*match)(const _EGLConfig *, void *),
722 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
723 void *),
724 void *priv_data)
725 {
726 _EGLConfig **configList;
727 EGLint i, count;
728
729 if (!num_configs)
730 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
731
732 /* get the number of matched configs */
733 count = _eglFilterArray(array, NULL, 0,
734 (_EGLArrayForEach) match, priv_data);
735 if (!count) {
736 *num_configs = count;
737 return EGL_TRUE;
738 }
739
740 configList = malloc(sizeof(*configList) * count);
741 if (!configList)
742 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
743
744 /* get the matched configs */
745 _eglFilterArray(array, (void **) configList, count,
746 (_EGLArrayForEach) match, priv_data);
747
748 /* perform sorting of configs */
749 if (configs && count) {
750 _eglSortConfigs((const _EGLConfig **) configList, count,
751 compare, priv_data);
752 count = MIN2(count, config_size);
753 for (i = 0; i < count; i++)
754 configs[i] = _eglGetConfigHandle(configList[i]);
755 }
756
757 free(configList);
758
759 *num_configs = count;
760
761 return EGL_TRUE;
762 }
763
764
765 static EGLBoolean
766 _eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
767 {
768 return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
769 }
770
771
772 static EGLint
773 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
774 void *priv_data)
775 {
776 return _eglCompareConfigs(conf1, conf2,
777 (const _EGLConfig *) priv_data, EGL_TRUE);
778 }
779
780
781 /**
782 * Typical fallback routine for eglChooseConfig
783 */
784 EGLBoolean
785 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
786 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
787 {
788 _EGLConfig criteria;
789
790 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
791 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
792
793 return _eglFilterConfigArray(disp->Configs,
794 configs, config_size, num_configs,
795 _eglFallbackMatch, _eglFallbackCompare,
796 (void *) &criteria);
797 }
798
799
800 /**
801 * Fallback for eglGetConfigAttrib.
802 */
803 EGLBoolean
804 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
805 EGLint attribute, EGLint *value)
806 {
807 if (!_eglIsConfigAttribValid(conf, attribute))
808 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
809
810 /* nonqueryable attributes */
811 switch (attribute) {
812 case EGL_MATCH_NATIVE_PIXMAP:
813 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
814 break;
815 default:
816 break;
817 }
818
819 if (!value)
820 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
821
822 *value = _eglGetConfigKey(conf, attribute);
823 return EGL_TRUE;
824 }
825
826
827 static EGLBoolean
828 _eglFlattenConfig(void *elem, void *buffer)
829 {
830 _EGLConfig *conf = (_EGLConfig *) elem;
831 EGLConfig *handle = (EGLConfig *) buffer;
832 *handle = _eglGetConfigHandle(conf);
833 return EGL_TRUE;
834 }
835
836 /**
837 * Fallback for eglGetConfigs.
838 */
839 EGLBoolean
840 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
841 EGLint config_size, EGLint *num_config)
842 {
843 if (!num_config)
844 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
845
846 *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
847 sizeof(configs[0]), config_size, _eglFlattenConfig);
848
849 return EGL_TRUE;
850 }