Merge branch 'mesa_7_5_branch'
[mesa.git] / src / egl / main / eglconfig.c
1 /**
2 * EGL Configuration (pixel format) functions.
3 */
4
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <assert.h>
10 #include "eglconfig.h"
11 #include "egldisplay.h"
12 #include "egldriver.h"
13 #include "eglglobals.h"
14 #include "egllog.h"
15
16
17 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
18
19
20 void
21 _eglSetConfigAttrib(_EGLConfig *config, EGLint attr, EGLint val)
22 {
23 assert(attr >= FIRST_ATTRIB);
24 assert(attr < FIRST_ATTRIB + MAX_ATTRIBS);
25 config->Attrib[attr - FIRST_ATTRIB] = val;
26 }
27
28
29 /**
30 * Init the given _EGLconfig to default values.
31 * \param id the configuration's ID.
32 */
33 void
34 _eglInitConfig(_EGLConfig *config, EGLint id)
35 {
36 memset(config, 0, sizeof(*config));
37 config->Handle = (EGLConfig) _eglUIntToPointer((unsigned int) id);
38 _eglSetConfigAttrib(config, EGL_CONFIG_ID, id);
39 _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE);
40 _eglSetConfigAttrib(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE);
41 _eglSetConfigAttrib(config, EGL_CONFIG_CAVEAT, EGL_DONT_CARE);
42 _eglSetConfigAttrib(config, EGL_NATIVE_RENDERABLE, EGL_DONT_CARE);
43 _eglSetConfigAttrib(config, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
44 _eglSetConfigAttrib(config, EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE);
45 _eglSetConfigAttrib(config, EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE);
46 _eglSetConfigAttrib(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
47 _eglSetConfigAttrib(config, EGL_TRANSPARENT_TYPE, EGL_NONE);
48 _eglSetConfigAttrib(config, EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE);
49 _eglSetConfigAttrib(config, EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE);
50 _eglSetConfigAttrib(config, EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE);
51 #ifdef EGL_VERSION_1_2
52 _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER);
53 _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT);
54 #endif /* EGL_VERSION_1_2 */
55 }
56
57
58 /**
59 * Return the public handle for an internal _EGLConfig.
60 * This is the inverse of _eglLookupConfig().
61 */
62 EGLConfig
63 _eglGetConfigHandle(_EGLConfig *config)
64 {
65 return config ? config->Handle : 0;
66 }
67
68
69 /**
70 * Given an EGLConfig handle, return the corresponding _EGLConfig object.
71 * This is the inverse of _eglGetConfigHandle().
72 */
73 _EGLConfig *
74 _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config)
75 {
76 EGLint i;
77 _EGLDisplay *disp = _eglLookupDisplay(dpy);
78 for (i = 0; i < disp->NumConfigs; i++) {
79 if (disp->Configs[i]->Handle == config) {
80 return disp->Configs[i];
81 }
82 }
83 return NULL;
84 }
85
86
87 /**
88 * Add the given _EGLConfig to the given display.
89 * Note that we just save the ptr to the config (we don't copy the config).
90 */
91 _EGLConfig *
92 _eglAddConfig(_EGLDisplay *display, _EGLConfig *config)
93 {
94 _EGLConfig **newConfigs;
95 EGLint n;
96
97 /* do some sanity checks on the config's attribs */
98 assert(GET_CONFIG_ATTRIB(config, EGL_CONFIG_ID) > 0);
99 assert(GET_CONFIG_ATTRIB(config, EGL_RENDERABLE_TYPE) != 0x0);
100 assert(GET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE) != 0x0);
101 assert(GET_CONFIG_ATTRIB(config, EGL_RED_SIZE) > 0);
102 assert(GET_CONFIG_ATTRIB(config, EGL_GREEN_SIZE) > 0);
103 assert(GET_CONFIG_ATTRIB(config, EGL_BLUE_SIZE) > 0);
104
105 n = display->NumConfigs;
106
107 /* realloc array of ptrs */
108 newConfigs = (_EGLConfig **) realloc(display->Configs,
109 (n + 1) * sizeof(_EGLConfig *));
110 if (newConfigs) {
111 display->Configs = newConfigs;
112 display->Configs[n] = config;
113 display->NumConfigs++;
114 return config;
115 }
116 else {
117 return NULL;
118 }
119 }
120
121
122 /**
123 * Parse the attrib_list to fill in the fields of the given _eglConfig
124 * Return EGL_FALSE if any errors, EGL_TRUE otherwise.
125 */
126 EGLBoolean
127 _eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list)
128 {
129 EGLint i;
130
131 /* set all config attribs to EGL_DONT_CARE */
132 for (i = 0; i < MAX_ATTRIBS; i++) {
133 config->Attrib[i] = EGL_DONT_CARE;
134 }
135
136 /* by default choose windows unless otherwise specified */
137 config->Attrib[EGL_SURFACE_TYPE - FIRST_ATTRIB] = EGL_WINDOW_BIT;
138
139 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
140 const EGLint attr = attrib_list[i];
141 if (attr >= EGL_BUFFER_SIZE &&
142 attr <= EGL_MAX_SWAP_INTERVAL) {
143 EGLint k = attr - FIRST_ATTRIB;
144 assert(k >= 0);
145 assert(k < MAX_ATTRIBS);
146 config->Attrib[k] = attrib_list[++i];
147 }
148 #ifdef EGL_VERSION_1_2
149 else if (attr == EGL_COLOR_BUFFER_TYPE) {
150 EGLint bufType = attrib_list[++i];
151 if (bufType != EGL_RGB_BUFFER && bufType != EGL_LUMINANCE_BUFFER) {
152 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
153 return EGL_FALSE;
154 }
155 _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, bufType);
156 }
157 else if (attr == EGL_RENDERABLE_TYPE) {
158 EGLint renType = attrib_list[++i];
159 if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENVG_BIT)) {
160 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
161 return EGL_FALSE;
162 }
163 _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, renType);
164 }
165 else if (attr == EGL_ALPHA_MASK_SIZE ||
166 attr == EGL_LUMINANCE_SIZE) {
167 EGLint value = attrib_list[++i];
168 _eglSetConfigAttrib(config, attr, value);
169 }
170 #endif /* EGL_VERSION_1_2 */
171 else {
172 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
173 return EGL_FALSE;
174 }
175 }
176 return EGL_TRUE;
177 }
178
179
180 #define EXACT 1
181 #define ATLEAST 2
182 #define MASK 3
183 #define SMALLER 4
184 #define SPECIAL 5
185 #define NONE 6
186
187 struct sort_info {
188 EGLint Attribute;
189 EGLint MatchCriteria;
190 EGLint SortOrder;
191 };
192
193 /* This encodes the info from Table 3.5 of the EGL spec, ordered by
194 * Sort Priority.
195 *
196 * XXX To do: EGL 1.2 attribs
197 */
198 static struct sort_info SortInfo[] = {
199 { EGL_CONFIG_CAVEAT, EXACT, SPECIAL },
200 { EGL_RED_SIZE, ATLEAST, SPECIAL },
201 { EGL_GREEN_SIZE, ATLEAST, SPECIAL },
202 { EGL_BLUE_SIZE, ATLEAST, SPECIAL },
203 { EGL_ALPHA_SIZE, ATLEAST, SPECIAL },
204 { EGL_BUFFER_SIZE, ATLEAST, SMALLER },
205 { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER },
206 { EGL_SAMPLES, ATLEAST, SMALLER },
207 { EGL_DEPTH_SIZE, ATLEAST, SMALLER },
208 { EGL_STENCIL_SIZE, ATLEAST, SMALLER },
209 { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL },
210 { EGL_CONFIG_ID, EXACT, SMALLER },
211 { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE },
212 { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE },
213 { EGL_LEVEL, EXACT, NONE },
214 { EGL_NATIVE_RENDERABLE, EXACT, NONE },
215 { EGL_MAX_SWAP_INTERVAL, EXACT, NONE },
216 { EGL_MIN_SWAP_INTERVAL, EXACT, NONE },
217 { EGL_SURFACE_TYPE, MASK, NONE },
218 { EGL_TRANSPARENT_TYPE, EXACT, NONE },
219 { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE },
220 { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE },
221 { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE },
222 { 0, 0, 0 }
223 };
224
225
226 /**
227 * Return EGL_TRUE if the attributes of c meet or exceed the minimums
228 * specified by min.
229 */
230 static EGLBoolean
231 _eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min)
232 {
233 EGLint i;
234 for (i = 0; SortInfo[i].Attribute != 0; i++) {
235 const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute);
236 if (mv != EGL_DONT_CARE) {
237 const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute);
238 if (SortInfo[i].MatchCriteria == EXACT) {
239 if (cv != mv) {
240 return EGL_FALSE;
241 }
242 }
243 else if (SortInfo[i].MatchCriteria == ATLEAST) {
244 if (cv < mv) {
245 return EGL_FALSE;
246 }
247 }
248 else {
249 assert(SortInfo[i].MatchCriteria == MASK);
250 if ((mv & cv) != mv) {
251 return EGL_FALSE;
252 }
253 }
254 }
255 }
256 return EGL_TRUE;
257 }
258
259
260 /**
261 * Compare configs 'a' and 'b' and return -1 if a belongs before b,
262 * 1 if a belongs after b, or 0 if they're equal.
263 * Used by qsort().
264 */
265 static int
266 _eglCompareConfigs(const void *a, const void *b)
267 {
268 const _EGLConfig *aConfig = (const _EGLConfig *) a;
269 const _EGLConfig *bConfig = (const _EGLConfig *) b;
270 EGLint i;
271
272 for (i = 0; SortInfo[i].Attribute != 0; i++) {
273 const EGLint aVal = GET_CONFIG_ATTRIB(aConfig, SortInfo[i].Attribute);
274 const EGLint bVal = GET_CONFIG_ATTRIB(bConfig, SortInfo[i].Attribute);
275 if (SortInfo[i].SortOrder == SMALLER) {
276 if (aVal < bVal)
277 return -1;
278 else if (aVal > bVal)
279 return 1;
280 /* else, continue examining attribute values */
281 }
282 else if (SortInfo[i].SortOrder == SPECIAL) {
283 if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) {
284 /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */
285 if (aVal < bVal)
286 return -1;
287 else if (aVal > bVal)
288 return 1;
289 }
290 else if (SortInfo[i].Attribute == EGL_RED_SIZE ||
291 SortInfo[i].Attribute == EGL_GREEN_SIZE ||
292 SortInfo[i].Attribute == EGL_BLUE_SIZE ||
293 SortInfo[i].Attribute == EGL_ALPHA_SIZE) {
294 if (aVal > bVal)
295 return -1;
296 else if (aVal < bVal)
297 return 1;
298 }
299 else {
300 assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE);
301 if (aVal < bVal)
302 return -1;
303 else if (aVal > bVal)
304 return 1;
305 }
306 }
307 else {
308 assert(SortInfo[i].SortOrder == NONE);
309 /* continue examining attribute values */
310 }
311 }
312
313 /* all attributes identical */
314 return 0;
315 }
316
317
318 /**
319 * Typical fallback routine for eglChooseConfig
320 */
321 EGLBoolean
322 _eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list,
323 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
324 {
325 _EGLDisplay *disp = _eglLookupDisplay(dpy);
326 _EGLConfig **configList, criteria;
327 EGLint i, count;
328
329 /* parse the attrib_list to initialize criteria */
330 if (!_eglParseConfigAttribs(&criteria, attrib_list)) {
331 return EGL_FALSE;
332 }
333
334 /* allocate array of config pointers */
335 configList = (_EGLConfig **) malloc(config_size * sizeof(_EGLConfig *));
336 if (!configList) {
337 _eglError(EGL_BAD_CONFIG, "eglChooseConfig(out of memory)");
338 return EGL_FALSE;
339 }
340
341 /* make array of pointers to qualifying configs */
342 for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) {
343 if (_eglConfigQualifies(disp->Configs[i], &criteria)) {
344 configList[count++] = disp->Configs[i];
345 }
346 }
347
348 /* sort array of pointers */
349 qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs);
350
351 /* copy config handles to output array */
352 if (configs) {
353 for (i = 0; i < count; i++) {
354 configs[i] = configList[i]->Handle;
355 }
356 }
357
358 free(configList);
359
360 *num_configs = count;
361
362 return EGL_TRUE;
363 }
364
365
366 /**
367 * Fallback for eglGetConfigAttrib.
368 */
369 EGLBoolean
370 _eglGetConfigAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
371 EGLint attribute, EGLint *value)
372 {
373 const _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
374 const EGLint k = attribute - FIRST_ATTRIB;
375 if (k >= 0 && k < MAX_ATTRIBS) {
376 *value = conf->Attrib[k];
377 return EGL_TRUE;
378 }
379 else {
380 _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
381 return EGL_FALSE;
382 }
383 }
384
385
386 /**
387 * Fallback for eglGetConfigs.
388 */
389 EGLBoolean
390 _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs,
391 EGLint config_size, EGLint *num_config)
392 {
393 _EGLDisplay *disp = _eglLookupDisplay(dpy);
394
395 if (!drv->Initialized) {
396 _eglError(EGL_NOT_INITIALIZED, "eglGetConfigs");
397 return EGL_FALSE;
398 }
399
400 if (configs) {
401 EGLint i;
402 *num_config = MIN2(disp->NumConfigs, config_size);
403 for (i = 0; i < *num_config; i++) {
404 configs[i] = disp->Configs[i]->Handle;
405 }
406 }
407 else {
408 /* just return total number of supported configs */
409 *num_config = disp->NumConfigs;
410 }
411
412 return EGL_TRUE;
413 }