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