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