1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * Copyright 2009-2010 Chia-I Wu <[email protected]>
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 { EGL_CONFIG_SELECT_GROUP_EXT, ATTRIB_TYPE_INTEGER,
253 ATTRIB_CRITERION_IGNORE,
254 0 },
255 /* clang-format on */
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
_eglValidateConfig(const _EGLConfig * conf,EGLBoolean for_matching)267 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
268 {
269 _EGLDisplay *disp = conf->Display;
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 case EGL_CONFIG_SELECT_GROUP_EXT:
294 break;
295 default:
296 if (val < 0)
297 valid = EGL_FALSE;
298 break;
299 }
300 break;
301 case ATTRIB_TYPE_BOOLEAN:
302 if (val != EGL_TRUE && val != EGL_FALSE)
303 valid = EGL_FALSE;
304 break;
305 case ATTRIB_TYPE_ENUM:
306 switch (attr) {
307 case EGL_CONFIG_CAVEAT:
308 if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
309 val != EGL_NON_CONFORMANT_CONFIG)
310 valid = EGL_FALSE;
311 break;
312 case EGL_TRANSPARENT_TYPE:
313 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
314 valid = EGL_FALSE;
315 break;
316 case EGL_COLOR_BUFFER_TYPE:
317 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
318 valid = EGL_FALSE;
319 break;
320 case EGL_COLOR_COMPONENT_TYPE_EXT:
321 if (val != EGL_COLOR_COMPONENT_TYPE_FIXED_EXT &&
322 val != EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT)
323 valid = EGL_FALSE;
324 break;
325 default:
326 unreachable("check _eglValidationTable[]");
327 break;
328 }
329 break;
330 case ATTRIB_TYPE_BITMASK:
331 switch (attr) {
332 case EGL_SURFACE_TYPE:
333 mask = EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT |
334 EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT |
335 EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
336 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
337 if (disp->Extensions.KHR_mutable_render_buffer)
338 mask |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR;
339 break;
340 case EGL_RENDERABLE_TYPE:
341 case EGL_CONFORMANT:
342 mask = EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT |
343 EGL_OPENGL_ES3_BIT_KHR | EGL_OPENGL_BIT;
344 break;
345 default:
346 unreachable("check _eglValidationTable[]");
347 mask = 0;
348 break;
349 }
350 if (val & ~mask)
351 valid = EGL_FALSE;
352 break;
353 case ATTRIB_TYPE_PLATFORM:
354 /* unable to check platform-dependent attributes here */
355 break;
356 case ATTRIB_TYPE_PSEUDO:
357 /* pseudo attributes should not be set */
358 if (val != 0)
359 valid = EGL_FALSE;
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, "attribute 0x%04x has an invalid value 0x%x", attr,
372 val);
373 break;
374 }
375 }
376
377 /* any invalid attribute value should have been caught */
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 + conf->BlueSize + conf->AlphaSize !=
388 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,
420 "conflicting surface type and native visual/texture binding");
421 return EGL_FALSE;
422 }
423
424 return valid;
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 case ATTRIB_CRITERION_IGNORE:
469 unreachable("already handled above");
470 break;
471 }
472
473 if (!matched) {
474 #if !MESA_DEBUG
475 /* only print the common errors when MESA_DEBUG is defined to 0 */
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 "
481 "criteria (0x%x)",
482 val, attr, cmp);
483 break;
484 }
485 }
486
487 return matched;
488 }
489
490 static inline EGLBoolean
_eglIsConfigAttribValid(const _EGLConfig * conf,EGLint attr)491 _eglIsConfigAttribValid(const _EGLConfig *conf, EGLint attr)
492 {
493 if (_eglOffsetOfConfig(attr) < 0)
494 return EGL_FALSE;
495
496 switch (attr) {
497 case EGL_Y_INVERTED_NOK:
498 return conf->Display->Extensions.NOK_texture_from_pixmap;
499 case EGL_FRAMEBUFFER_TARGET_ANDROID:
500 return conf->Display->Extensions.ANDROID_framebuffer_target;
501 case EGL_RECORDABLE_ANDROID:
502 return conf->Display->Extensions.ANDROID_recordable;
503 default:
504 break;
505 }
506
507 return EGL_TRUE;
508 }
509
510 /**
511 * Initialize a criteria config from the given attribute list.
512 * Return EGL_FALSE if any of the attribute is invalid.
513 */
514 EGLBoolean
_eglParseConfigAttribList(_EGLConfig * conf,_EGLDisplay * disp,const EGLint * attrib_list)515 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp,
516 const EGLint *attrib_list)
517 {
518 EGLint attr, val, i;
519
520 _eglInitConfig(conf, disp, EGL_DONT_CARE);
521
522 /* reset to default values */
523 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
524 attr = _eglValidationTable[i].attr;
525 val = _eglValidationTable[i].default_value;
526 _eglSetConfigKey(conf, attr, val);
527 }
528
529 /* parse the list */
530 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
531 attr = attrib_list[i];
532 val = attrib_list[i + 1];
533
534 if (!_eglIsConfigAttribValid(conf, attr))
535 return EGL_FALSE;
536
537 _eglSetConfigKey(conf, attr, val);
538 }
539
540 if (!_eglValidateConfig(conf, EGL_TRUE))
541 return EGL_FALSE;
542
543 /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
544 if (conf->Level == EGL_DONT_CARE || 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 } 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 * Decide the ordering of conf1 and conf2, under the given criteria.
570 * When compare_id is true, this implements the algorithm described
571 * in "Sorting of EGLConfigs". When compare_id is false,
572 * EGL_CONFIG_ID is not compared.
573 *
574 * It returns a negative integer if conf1 is considered to come
575 * before conf2; a positive integer if conf2 is considered to come
576 * before conf1; zero if the ordering cannot be decided.
577 *
578 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
579 * ignored here.
580 */
581 EGLint
_eglCompareConfigs(const _EGLConfig * conf1,const _EGLConfig * conf2,const _EGLConfig * criteria,EGLBoolean compare_id)582 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
583 const _EGLConfig *criteria, EGLBoolean compare_id)
584 {
585 const EGLint compare_attribs[] = {
586 EGL_BUFFER_SIZE, EGL_SAMPLE_BUFFERS, EGL_SAMPLES,
587 EGL_DEPTH_SIZE, EGL_STENCIL_SIZE, EGL_ALPHA_MASK_SIZE,
588 };
589 EGLint val1, val2;
590 EGLint i;
591
592 if (conf1 == conf2)
593 return 0;
594
595 val1 = conf1->ConfigSelectGroup - conf2->ConfigSelectGroup;
596 if (val1)
597 return val1;
598
599 /* the enum values have the desired ordering */
600 STATIC_ASSERT(EGL_NONE < EGL_SLOW_CONFIG);
601 STATIC_ASSERT(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
602 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
603 if (val1)
604 return val1;
605
606 /* the enum values have the desired ordering */
607 STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
608 val1 = conf1->ColorBufferType - conf2->ColorBufferType;
609 if (val1)
610 return val1;
611
612 if (criteria) {
613 val1 = val2 = 0;
614 if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
615 if (criteria->RedSize > 0) {
616 val1 += conf1->RedSize;
617 val2 += conf2->RedSize;
618 }
619 if (criteria->GreenSize > 0) {
620 val1 += conf1->GreenSize;
621 val2 += conf2->GreenSize;
622 }
623 if (criteria->BlueSize > 0) {
624 val1 += conf1->BlueSize;
625 val2 += conf2->BlueSize;
626 }
627 } else {
628 if (criteria->LuminanceSize > 0) {
629 val1 += conf1->LuminanceSize;
630 val2 += conf2->LuminanceSize;
631 }
632 }
633 if (criteria->AlphaSize > 0) {
634 val1 += conf1->AlphaSize;
635 val2 += conf2->AlphaSize;
636 }
637 } else {
638 /* assume the default criteria, which gives no specific ordering */
639 val1 = val2 = 0;
640 }
641
642 /* for color bits, larger one is preferred */
643 if (val1 != val2)
644 return (val2 - val1);
645
646 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
647 val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
648 val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
649 if (val1 != val2)
650 return (val1 - val2);
651 }
652
653 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
654
655 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
656 }
657
658 static inline void
_eglSwapConfigs(const _EGLConfig ** conf1,const _EGLConfig ** conf2)659 _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
660 {
661 const _EGLConfig *tmp = *conf1;
662 *conf1 = *conf2;
663 *conf2 = tmp;
664 }
665
666 /**
667 * Quick sort an array of configs. This differs from the standard
668 * qsort() in that the compare function accepts an additional
669 * argument.
670 */
671 static void
_eglSortConfigs(const _EGLConfig ** configs,EGLint count,EGLint (* compare)(const _EGLConfig *,const _EGLConfig *,void *),void * priv_data)672 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
673 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
674 void *),
675 void *priv_data)
676 {
677 const EGLint pivot = 0;
678 EGLint i, j;
679
680 if (count <= 1)
681 return;
682
683 _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
684 i = 1;
685 j = count - 1;
686 do {
687 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
688 i++;
689 while (compare(configs[j], configs[pivot], priv_data) > 0)
690 j--;
691 if (i < j) {
692 _eglSwapConfigs(&configs[i], &configs[j]);
693 i++;
694 j--;
695 } else if (i == j) {
696 i++;
697 j--;
698 break;
699 }
700 } while (i <= j);
701 _eglSwapConfigs(&configs[pivot], &configs[j]);
702
703 _eglSortConfigs(configs, j, compare, priv_data);
704 _eglSortConfigs(configs + i, count - i, compare, priv_data);
705 }
706
707 /**
708 * A helper function for implementing eglChooseConfig. See _eglFilterArray and
709 * _eglSortConfigs for the meanings of match and compare.
710 */
711 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)712 _eglFilterConfigArray(_EGLArray *array, EGLConfig *configs, EGLint config_size,
713 EGLint *num_configs,
714 EGLBoolean (*match)(const _EGLConfig *,
715 const _EGLConfig *),
716 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
717 void *),
718 void *priv_data)
719 {
720 _EGLConfig **configList;
721 EGLint i, count;
722
723 /* get the number of matched configs */
724 count = _eglFilterArray(array, NULL, 0, (_EGLArrayForEach)match, priv_data);
725 if (!count) {
726 *num_configs = count;
727 return EGL_TRUE;
728 }
729
730 configList = malloc(sizeof(*configList) * count);
731 if (!configList)
732 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
733
734 /* get the matched configs */
735 _eglFilterArray(array, (void **)configList, count, (_EGLArrayForEach)match,
736 priv_data);
737
738 /* perform sorting of configs */
739 if (configs && count) {
740 _eglSortConfigs((const _EGLConfig **)configList, count, compare,
741 priv_data);
742 count = MIN2(count, config_size);
743 for (i = 0; i < count; i++)
744 configs[i] = _eglGetConfigHandle(configList[i]);
745 }
746
747 free(configList);
748
749 *num_configs = count;
750
751 return EGL_TRUE;
752 }
753
754 static EGLint
_eglFallbackCompare(const _EGLConfig * conf1,const _EGLConfig * conf2,void * priv_data)755 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
756 void *priv_data)
757 {
758 return _eglCompareConfigs(conf1, conf2, (const _EGLConfig *)priv_data,
759 EGL_TRUE);
760 }
761
762 /**
763 * Typical fallback routine for eglChooseConfig
764 */
765 EGLBoolean
_eglChooseConfig(_EGLDisplay * disp,const EGLint * attrib_list,EGLConfig * configs,EGLint config_size,EGLint * num_configs)766 _eglChooseConfig(_EGLDisplay *disp, const EGLint *attrib_list,
767 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
768 {
769 _EGLConfig criteria;
770 EGLBoolean result;
771
772 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
773 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
774
775 result = _eglFilterConfigArray(disp->Configs, configs, config_size,
776 num_configs, _eglMatchConfig,
777 _eglFallbackCompare, (void *)&criteria);
778
779 if (result && (_eglGetLogLevel() == _EGL_DEBUG))
780 eglPrintConfigDebug(disp, configs, *num_configs, EGL_TRUE);
781
782 return result;
783 }
784
785 /**
786 * Fallback for eglGetConfigAttrib.
787 */
788 EGLBoolean
_eglGetConfigAttrib(const _EGLDisplay * disp,const _EGLConfig * conf,EGLint attribute,EGLint * value)789 _eglGetConfigAttrib(const _EGLDisplay *disp, const _EGLConfig *conf,
790 EGLint attribute, EGLint *value)
791 {
792 if (!_eglIsConfigAttribValid(conf, attribute))
793 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
794
795 /* nonqueryable attributes */
796 switch (attribute) {
797 case EGL_MATCH_NATIVE_PIXMAP:
798 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
799 break;
800 default:
801 break;
802 }
803
804 if (!value)
805 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
806
807 *value = _eglGetConfigKey(conf, attribute);
808 return EGL_TRUE;
809 }
810
811 static EGLBoolean
_eglFlattenConfig(void * elem,void * buffer)812 _eglFlattenConfig(void *elem, void *buffer)
813 {
814 _EGLConfig *conf = (_EGLConfig *)elem;
815 EGLConfig *handle = (EGLConfig *)buffer;
816 *handle = _eglGetConfigHandle(conf);
817 return EGL_TRUE;
818 }
819
820 /**
821 * Fallback for eglGetConfigs.
822 */
823 EGLBoolean
_eglGetConfigs(_EGLDisplay * disp,EGLConfig * configs,EGLint config_size,EGLint * num_config)824 _eglGetConfigs(_EGLDisplay *disp, EGLConfig *configs, EGLint config_size,
825 EGLint *num_config)
826 {
827 *num_config =
828 _eglFlattenArray(disp->Configs, (void *)configs, sizeof(configs[0]),
829 config_size, _eglFlattenConfig);
830
831 if (_eglGetLogLevel() == _EGL_DEBUG)
832 eglPrintConfigDebug(disp, configs, *num_config, EGL_FALSE);
833
834 return EGL_TRUE;
835 }
836