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