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