• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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