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