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