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