1 /**************************************************************************
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright 2010-2011 LunarG, Inc.
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:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
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.
28 **************************************************************************/
32 * EGL Configuration (pixel format) functions.
39 #include "eglconfig.h"
40 #include "egldisplay.h"
41 #include "eglcurrent.h"
45 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
49 * Init the given _EGLconfig to default values.
50 * \param id the configuration's ID.
52 * Note that id must be positive for the config to be valid.
53 * It is also recommended that when there are N configs, their
54 * IDs are from 1 to N respectively.
57 _eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
59 memset(conf, 0, sizeof(*conf));
63 /* some attributes take non-zero default values */
65 conf->ConfigCaveat = EGL_NONE;
66 conf->TransparentType = EGL_NONE;
67 conf->NativeVisualType = EGL_NONE;
68 conf->ColorBufferType = EGL_RGB_BUFFER;
73 * Link a config to its display and return the handle of the link.
74 * The handle can be passed to client directly.
76 * Note that we just save the ptr to the config (we don't copy the config).
79 _eglLinkConfig(_EGLConfig *conf)
81 _EGLDisplay *dpy = conf->Display;
84 assert(dpy && conf->ConfigID > 0);
87 dpy->Configs = _eglCreateArray("Config", 16);
89 return (EGLConfig) NULL;
92 _eglAppendArray(dpy->Configs, (void *) conf);
94 return (EGLConfig) conf;
99 * Lookup a handle to find the linked config.
100 * Return NULL if the handle has no corresponding linked config.
103 _eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
110 conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
112 assert(conf->Display == dpy);
124 ATTRIB_TYPE_PSEUDO, /* non-queryable */
125 ATTRIB_TYPE_PLATFORM, /* platform-dependent */
127 ATTRIB_CRITERION_EXACT,
128 ATTRIB_CRITERION_ATLEAST,
129 ATTRIB_CRITERION_MASK,
130 ATTRIB_CRITERION_SPECIAL,
131 ATTRIB_CRITERION_IGNORE
135 /* EGL spec Table 3.1 and 3.4 */
136 static const struct {
140 EGLint default_value;
141 } _eglValidationTable[] =
144 { EGL_BUFFER_SIZE, ATTRIB_TYPE_INTEGER,
145 ATTRIB_CRITERION_ATLEAST,
147 { EGL_RED_SIZE, ATTRIB_TYPE_INTEGER,
148 ATTRIB_CRITERION_ATLEAST,
150 { EGL_GREEN_SIZE, ATTRIB_TYPE_INTEGER,
151 ATTRIB_CRITERION_ATLEAST,
153 { EGL_BLUE_SIZE, ATTRIB_TYPE_INTEGER,
154 ATTRIB_CRITERION_ATLEAST,
156 { EGL_LUMINANCE_SIZE, ATTRIB_TYPE_INTEGER,
157 ATTRIB_CRITERION_ATLEAST,
159 { EGL_ALPHA_SIZE, ATTRIB_TYPE_INTEGER,
160 ATTRIB_CRITERION_ATLEAST,
162 { EGL_ALPHA_MASK_SIZE, ATTRIB_TYPE_INTEGER,
163 ATTRIB_CRITERION_ATLEAST,
165 { EGL_BIND_TO_TEXTURE_RGB, ATTRIB_TYPE_BOOLEAN,
166 ATTRIB_CRITERION_EXACT,
168 { EGL_BIND_TO_TEXTURE_RGBA, ATTRIB_TYPE_BOOLEAN,
169 ATTRIB_CRITERION_EXACT,
171 { EGL_COLOR_BUFFER_TYPE, ATTRIB_TYPE_ENUM,
172 ATTRIB_CRITERION_EXACT,
174 { EGL_CONFIG_CAVEAT, ATTRIB_TYPE_ENUM,
175 ATTRIB_CRITERION_EXACT,
177 { EGL_CONFIG_ID, ATTRIB_TYPE_INTEGER,
178 ATTRIB_CRITERION_EXACT,
180 { EGL_CONFORMANT, ATTRIB_TYPE_BITMASK,
181 ATTRIB_CRITERION_MASK,
183 { EGL_DEPTH_SIZE, ATTRIB_TYPE_INTEGER,
184 ATTRIB_CRITERION_ATLEAST,
186 { EGL_LEVEL, ATTRIB_TYPE_PLATFORM,
187 ATTRIB_CRITERION_EXACT,
189 { EGL_MAX_PBUFFER_WIDTH, ATTRIB_TYPE_INTEGER,
190 ATTRIB_CRITERION_IGNORE,
192 { EGL_MAX_PBUFFER_HEIGHT, ATTRIB_TYPE_INTEGER,
193 ATTRIB_CRITERION_IGNORE,
195 { EGL_MAX_PBUFFER_PIXELS, ATTRIB_TYPE_INTEGER,
196 ATTRIB_CRITERION_IGNORE,
198 { EGL_MAX_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
199 ATTRIB_CRITERION_EXACT,
201 { EGL_MIN_SWAP_INTERVAL, ATTRIB_TYPE_INTEGER,
202 ATTRIB_CRITERION_EXACT,
204 { EGL_NATIVE_RENDERABLE, ATTRIB_TYPE_BOOLEAN,
205 ATTRIB_CRITERION_EXACT,
207 { EGL_NATIVE_VISUAL_ID, ATTRIB_TYPE_PLATFORM,
208 ATTRIB_CRITERION_IGNORE,
210 { EGL_NATIVE_VISUAL_TYPE, ATTRIB_TYPE_PLATFORM,
211 ATTRIB_CRITERION_EXACT,
213 { EGL_RENDERABLE_TYPE, ATTRIB_TYPE_BITMASK,
214 ATTRIB_CRITERION_MASK,
216 { EGL_SAMPLE_BUFFERS, ATTRIB_TYPE_INTEGER,
217 ATTRIB_CRITERION_ATLEAST,
219 { EGL_SAMPLES, ATTRIB_TYPE_INTEGER,
220 ATTRIB_CRITERION_ATLEAST,
222 { EGL_STENCIL_SIZE, ATTRIB_TYPE_INTEGER,
223 ATTRIB_CRITERION_ATLEAST,
225 { EGL_SURFACE_TYPE, ATTRIB_TYPE_BITMASK,
226 ATTRIB_CRITERION_MASK,
228 { EGL_TRANSPARENT_TYPE, ATTRIB_TYPE_ENUM,
229 ATTRIB_CRITERION_EXACT,
231 { EGL_TRANSPARENT_RED_VALUE, ATTRIB_TYPE_INTEGER,
232 ATTRIB_CRITERION_EXACT,
234 { EGL_TRANSPARENT_GREEN_VALUE, ATTRIB_TYPE_INTEGER,
235 ATTRIB_CRITERION_EXACT,
237 { EGL_TRANSPARENT_BLUE_VALUE, ATTRIB_TYPE_INTEGER,
238 ATTRIB_CRITERION_EXACT,
240 { EGL_MATCH_NATIVE_PIXMAP, ATTRIB_TYPE_PSEUDO,
241 ATTRIB_CRITERION_SPECIAL,
244 { EGL_Y_INVERTED_NOK, ATTRIB_TYPE_BOOLEAN,
245 ATTRIB_CRITERION_EXACT,
251 * Return true if a config is valid. When for_matching is true,
252 * EGL_DONT_CARE is accepted as a valid attribute value, and checks
253 * for conflicting attribute values are skipped.
255 * Note that some attributes are platform-dependent and are not
259 _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
262 EGLBoolean valid = EGL_TRUE;
264 /* check attributes by their types */
265 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
268 attr = _eglValidationTable[i].attr;
269 val = _eglGetConfigKey(conf, attr);
271 switch (_eglValidationTable[i].type) {
272 case ATTRIB_TYPE_INTEGER:
275 /* config id must be positive */
279 case EGL_SAMPLE_BUFFERS:
280 /* there can be at most 1 sample buffer */
281 if (val > 1 || val < 0)
290 case ATTRIB_TYPE_BOOLEAN:
291 if (val != EGL_TRUE && val != EGL_FALSE)
294 case ATTRIB_TYPE_ENUM:
296 case EGL_CONFIG_CAVEAT:
297 if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
298 val != EGL_NON_CONFORMANT_CONFIG)
301 case EGL_TRANSPARENT_TYPE:
302 if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
305 case EGL_COLOR_BUFFER_TYPE:
306 if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
314 case ATTRIB_TYPE_BITMASK:
316 case EGL_SURFACE_TYPE:
317 mask = EGL_PBUFFER_BIT |
320 EGL_VG_COLORSPACE_LINEAR_BIT |
321 EGL_VG_ALPHA_FORMAT_PRE_BIT |
322 EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
323 EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
324 #ifdef EGL_MESA_screen_surface
325 if (conf->Display->Extensions.MESA_screen_surface)
326 mask |= EGL_SCREEN_BIT_MESA;
329 case EGL_RENDERABLE_TYPE:
331 mask = EGL_OPENGL_ES_BIT |
343 case ATTRIB_TYPE_PLATFORM:
344 /* unable to check platform-dependent attributes here */
346 case ATTRIB_TYPE_PSEUDO:
347 /* pseudo attributes should not be set */
356 if (!valid && for_matching) {
357 /* accept EGL_DONT_CARE as a valid value */
358 if (val == EGL_DONT_CARE)
360 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
365 "attribute 0x%04x has an invalid value 0x%x", attr, val);
370 /* any invalid attribute value should have been catched */
371 if (!valid || for_matching)
374 /* now check for conflicting attribute values */
376 switch (conf->ColorBufferType) {
378 if (conf->LuminanceSize)
380 if (conf->RedSize + conf->GreenSize +
381 conf->BlueSize + conf->AlphaSize != conf->BufferSize)
384 case EGL_LUMINANCE_BUFFER:
385 if (conf->RedSize || conf->GreenSize || conf->BlueSize)
387 if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
392 _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
396 if (!conf->SampleBuffers && conf->Samples)
399 _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
403 if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
404 if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
407 if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
408 if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
412 _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
421 * Return true if a config matches the criteria. This and
422 * _eglParseConfigAttribList together implement the algorithm
423 * described in "Selection of EGLConfigs".
425 * Note that attributes that are special (currently, only
426 * EGL_MATCH_NATIVE_PIXMAP) are ignored.
429 _eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
432 EGLBoolean matched = EGL_TRUE;
434 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
436 if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
439 attr = _eglValidationTable[i].attr;
440 cmp = _eglGetConfigKey(criteria, attr);
441 if (cmp == EGL_DONT_CARE)
444 val = _eglGetConfigKey(conf, attr);
445 switch (_eglValidationTable[i].criterion) {
446 case ATTRIB_CRITERION_EXACT:
450 case ATTRIB_CRITERION_ATLEAST:
454 case ATTRIB_CRITERION_MASK:
455 if ((val & cmp) != cmp)
458 case ATTRIB_CRITERION_SPECIAL:
468 /* only print the common errors when DEBUG is not defined */
469 if (attr != EGL_RENDERABLE_TYPE)
473 "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
482 static INLINE EGLBoolean
483 _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
485 if (_eglOffsetOfConfig(attr) < 0)
489 case EGL_Y_INVERTED_NOK:
490 return conf->Display->Extensions.NOK_texture_from_pixmap;
499 * Initialize a criteria config from the given attribute list.
500 * Return EGL_FALSE if any of the attribute is invalid.
503 _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
504 const EGLint *attrib_list)
508 _eglInitConfig(conf, dpy, EGL_DONT_CARE);
510 /* reset to default values */
511 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
512 attr = _eglValidationTable[i].attr;
513 val = _eglValidationTable[i].default_value;
514 _eglSetConfigKey(conf, attr, val);
518 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
519 attr = attrib_list[i];
520 val = attrib_list[i + 1];
522 if (!_eglIsConfigAttribValid(conf, attr))
525 _eglSetConfigKey(conf, attr, val);
528 if (!_eglValidateConfig(conf, EGL_TRUE))
531 /* the spec says that EGL_LEVEL cannot be EGL_DONT_CARE */
532 if (conf->Level == EGL_DONT_CARE)
535 /* ignore other attributes when EGL_CONFIG_ID is given */
536 if (conf->ConfigID != EGL_DONT_CARE) {
537 for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
538 attr = _eglValidationTable[i].attr;
539 if (attr != EGL_CONFIG_ID)
540 _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
544 if (!(conf->SurfaceType & EGL_WINDOW_BIT))
545 conf->NativeVisualType = EGL_DONT_CARE;
547 if (conf->TransparentType == EGL_NONE) {
548 conf->TransparentRedValue = EGL_DONT_CARE;
549 conf->TransparentGreenValue = EGL_DONT_CARE;
550 conf->TransparentBlueValue = EGL_DONT_CARE;
559 * Decide the ordering of conf1 and conf2, under the given criteria.
560 * When compare_id is true, this implements the algorithm described
561 * in "Sorting of EGLConfigs". When compare_id is false,
562 * EGL_CONFIG_ID is not compared.
564 * It returns a negative integer if conf1 is considered to come
565 * before conf2; a positive integer if conf2 is considered to come
566 * before conf1; zero if the ordering cannot be decided.
568 * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
572 _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
573 const _EGLConfig *criteria, EGLBoolean compare_id)
575 const EGLint compare_attribs[] = {
589 /* the enum values have the desired ordering */
590 assert(EGL_NONE < EGL_SLOW_CONFIG);
591 assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
592 val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
596 /* the enum values have the desired ordering */
597 assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
598 val1 = conf1->ColorBufferType - conf2->ColorBufferType;
604 if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
605 if (criteria->RedSize > 0) {
606 val1 += conf1->RedSize;
607 val2 += conf2->RedSize;
609 if (criteria->GreenSize > 0) {
610 val1 += conf1->GreenSize;
611 val2 += conf2->GreenSize;
613 if (criteria->BlueSize > 0) {
614 val1 += conf1->BlueSize;
615 val2 += conf2->BlueSize;
619 if (criteria->LuminanceSize > 0) {
620 val1 += conf1->LuminanceSize;
621 val2 += conf2->LuminanceSize;
624 if (criteria->AlphaSize > 0) {
625 val1 += conf1->AlphaSize;
626 val2 += conf2->AlphaSize;
630 /* assume the default criteria, which gives no specific ordering */
634 /* for color bits, larger one is preferred */
636 return (val2 - val1);
638 for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
639 val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
640 val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
642 return (val1 - val2);
645 /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
647 return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
652 void _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
654 const _EGLConfig *tmp = *conf1;
661 * Quick sort an array of configs. This differs from the standard
662 * qsort() in that the compare function accepts an additional
666 _eglSortConfigs(const _EGLConfig **configs, EGLint count,
667 EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
671 const EGLint pivot = 0;
677 _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
681 while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
683 while (compare(configs[j], configs[pivot], priv_data) > 0)
686 _eglSwapConfigs(&configs[i], &configs[j]);
696 _eglSwapConfigs(&configs[pivot], &configs[j]);
698 _eglSortConfigs(configs, j, compare, priv_data);
699 _eglSortConfigs(configs + i, count - i, compare, priv_data);
704 _eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
707 const _EGLConfig *criteria = (const _EGLConfig *) priv_data;
708 return _eglCompareConfigs(conf1, conf2, criteria, EGL_TRUE);
713 * Typical fallback routine for eglChooseConfig
716 _eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
717 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
719 _EGLConfig **configList, criteria;
723 return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
725 if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
726 return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
728 /* get the number of matched configs */
729 count = _eglFilterArray(disp->Configs, NULL, 0,
730 (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria);
732 *num_configs = count;
736 configList = malloc(sizeof(*configList) * count);
738 return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
740 /* get the matched configs */
741 _eglFilterArray(disp->Configs, (void **) configList, count,
742 (_EGLArrayForEach) _eglMatchConfig, (void *) &criteria);
744 /* perform sorting of configs */
745 if (configs && count) {
746 _eglSortConfigs((const _EGLConfig **) configList, count,
747 _eglFallbackCompare, (void *) &criteria);
748 count = MIN2(count, config_size);
749 for (i = 0; i < count; i++)
750 configs[i] = _eglGetConfigHandle(configList[i]);
755 *num_configs = count;
762 * Fallback for eglGetConfigAttrib.
765 _eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
766 EGLint attribute, EGLint *value)
768 if (!_eglIsConfigAttribValid(conf, attribute))
769 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
771 /* nonqueryable attributes */
773 case EGL_MATCH_NATIVE_PIXMAP:
774 return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
781 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
783 *value = _eglGetConfigKey(conf, attribute);
789 _eglFlattenConfig(void *elem, void *buffer)
791 _EGLConfig *conf = (_EGLConfig *) elem;
792 EGLConfig *handle = (EGLConfig *) buffer;
793 *handle = _eglGetConfigHandle(conf);
798 * Fallback for eglGetConfigs.
801 _eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
802 EGLint config_size, EGLint *num_config)
805 return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
807 *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
808 sizeof(configs[0]), config_size, _eglFlattenConfig);