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