Merge commit 'origin/master' into gallium-0.2
[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) 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 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
137 const EGLint attr = attrib_list[i];
138 if (attr >= EGL_BUFFER_SIZE &&
139 attr <= EGL_MAX_SWAP_INTERVAL) {
140 EGLint k = attr - FIRST_ATTRIB;
141 assert(k >= 0);
142 assert(k < MAX_ATTRIBS);
143 config->Attrib[k] = attrib_list[++i];
144 }
145 #ifdef EGL_VERSION_1_2
146 else if (attr == EGL_COLOR_BUFFER_TYPE) {
147 EGLint bufType = attrib_list[++i];
148 if (bufType != EGL_RGB_BUFFER && bufType != EGL_LUMINANCE_BUFFER) {
149 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
150 return EGL_FALSE;
151 }
152 _eglSetConfigAttrib(config, EGL_COLOR_BUFFER_TYPE, bufType);
153 }
154 else if (attr == EGL_RENDERABLE_TYPE) {
155 EGLint renType = attrib_list[++i];
156 if (renType & ~(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENVG_BIT)) {
157 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
158 return EGL_FALSE;
159 }
160 _eglSetConfigAttrib(config, EGL_RENDERABLE_TYPE, renType);
161 }
162 else if (attr == EGL_ALPHA_MASK_SIZE ||
163 attr == EGL_LUMINANCE_SIZE) {
164 EGLint value = attrib_list[++i];
165 _eglSetConfigAttrib(config, attr, value);
166 }
167 #endif /* EGL_VERSION_1_2 */
168 else {
169 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
170 return EGL_FALSE;
171 }
172 }
173 return EGL_TRUE;
174 }
175
176
177 #define EXACT 1
178 #define ATLEAST 2
179 #define MASK 3
180 #define SMALLER 4
181 #define SPECIAL 5
182 #define NONE 6
183
184 struct sort_info {
185 EGLint Attribute;
186 EGLint MatchCriteria;
187 EGLint SortOrder;
188 };
189
190 /* This encodes the info from Table 3.5 of the EGL spec, ordered by
191 * Sort Priority.
192 *
193 * XXX To do: EGL 1.2 attribs
194 */
195 static struct sort_info SortInfo[] = {
196 { EGL_CONFIG_CAVEAT, EXACT, SPECIAL },
197 { EGL_RED_SIZE, ATLEAST, SPECIAL },
198 { EGL_GREEN_SIZE, ATLEAST, SPECIAL },
199 { EGL_BLUE_SIZE, ATLEAST, SPECIAL },
200 { EGL_ALPHA_SIZE, ATLEAST, SPECIAL },
201 { EGL_BUFFER_SIZE, ATLEAST, SMALLER },
202 { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER },
203 { EGL_SAMPLES, ATLEAST, SMALLER },
204 { EGL_DEPTH_SIZE, ATLEAST, SMALLER },
205 { EGL_STENCIL_SIZE, ATLEAST, SMALLER },
206 { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL },
207 { EGL_CONFIG_ID, EXACT, SMALLER },
208 { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE },
209 { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE },
210 { EGL_LEVEL, EXACT, NONE },
211 { EGL_NATIVE_RENDERABLE, EXACT, NONE },
212 { EGL_MAX_SWAP_INTERVAL, EXACT, NONE },
213 { EGL_MIN_SWAP_INTERVAL, EXACT, NONE },
214 { EGL_SURFACE_TYPE, MASK, NONE },
215 { EGL_TRANSPARENT_TYPE, EXACT, NONE },
216 { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE },
217 { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE },
218 { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE },
219 { 0, 0, 0 }
220 };
221
222
223 /**
224 * Return EGL_TRUE if the attributes of c meet or exceed the minimums
225 * specified by min.
226 */
227 static EGLBoolean
228 _eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min)
229 {
230 EGLint i;
231 for (i = 0; SortInfo[i].Attribute != 0; i++) {
232 const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute);
233 if (mv != EGL_DONT_CARE) {
234 const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute);
235 if (SortInfo[i].MatchCriteria == EXACT) {
236 if (cv != mv) {
237 return EGL_FALSE;
238 }
239 }
240 else if (SortInfo[i].MatchCriteria == ATLEAST) {
241 if (cv < mv) {
242 return EGL_FALSE;
243 }
244 }
245 else {
246 assert(SortInfo[i].MatchCriteria == MASK);
247 if ((mv & cv) != mv) {
248 return EGL_FALSE;
249 }
250 }
251 }
252 }
253 return EGL_TRUE;
254 }
255
256
257 /**
258 * Compare configs 'a' and 'b' and return -1 if a belongs before b,
259 * 1 if a belongs after b, or 0 if they're equal.
260 * Used by qsort().
261 */
262 static int
263 _eglCompareConfigs(const void *a, const void *b)
264 {
265 const _EGLConfig *aConfig = (const _EGLConfig *) a;
266 const _EGLConfig *bConfig = (const _EGLConfig *) b;
267 EGLint i;
268
269 for (i = 0; SortInfo[i].Attribute != 0; i++) {
270 const EGLint aVal = GET_CONFIG_ATTRIB(aConfig, SortInfo[i].Attribute);
271 const EGLint bVal = GET_CONFIG_ATTRIB(bConfig, SortInfo[i].Attribute);
272 if (SortInfo[i].SortOrder == SMALLER) {
273 if (aVal < bVal)
274 return -1;
275 else if (aVal > bVal)
276 return 1;
277 /* else, continue examining attribute values */
278 }
279 else if (SortInfo[i].SortOrder == SPECIAL) {
280 if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) {
281 /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */
282 if (aVal < bVal)
283 return -1;
284 else if (aVal > bVal)
285 return 1;
286 }
287 else if (SortInfo[i].Attribute == EGL_RED_SIZE ||
288 SortInfo[i].Attribute == EGL_GREEN_SIZE ||
289 SortInfo[i].Attribute == EGL_BLUE_SIZE ||
290 SortInfo[i].Attribute == EGL_ALPHA_SIZE) {
291 if (aVal > bVal)
292 return -1;
293 else if (aVal < bVal)
294 return 1;
295 }
296 else {
297 assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE);
298 if (aVal < bVal)
299 return -1;
300 else if (aVal > bVal)
301 return 1;
302 }
303 }
304 else {
305 assert(SortInfo[i].SortOrder == NONE);
306 /* continue examining attribute values */
307 }
308 }
309
310 /* all attributes identical */
311 return 0;
312 }
313
314
315 /**
316 * Typical fallback routine for eglChooseConfig
317 */
318 EGLBoolean
319 _eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list,
320 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
321 {
322 _EGLDisplay *disp = _eglLookupDisplay(dpy);
323 _EGLConfig **configList, criteria;
324 EGLint i, count;
325
326 /* parse the attrib_list to initialize criteria */
327 if (!_eglParseConfigAttribs(&criteria, attrib_list)) {
328 return EGL_FALSE;
329 }
330
331 /* allocate array of config pointers */
332 configList = (_EGLConfig **) malloc(config_size * sizeof(_EGLConfig *));
333 if (!configList) {
334 _eglError(EGL_BAD_CONFIG, "eglChooseConfig(out of memory)");
335 return EGL_FALSE;
336 }
337
338 /* make array of pointers to qualifying configs */
339 for (i = count = 0; i < disp->NumConfigs && count < config_size; i++) {
340 if (_eglConfigQualifies(disp->Configs[i], &criteria)) {
341 configList[count++] = disp->Configs[i];
342 }
343 }
344
345 /* sort array of pointers */
346 qsort(configList, count, sizeof(_EGLConfig *), _eglCompareConfigs);
347
348 /* copy config handles to output array */
349 if (configs) {
350 for (i = 0; i < count; i++) {
351 configs[i] = configList[i]->Handle;
352 }
353 }
354
355 free(configList);
356
357 *num_configs = count;
358
359 return EGL_TRUE;
360 }
361
362
363 /**
364 * Fallback for eglGetConfigAttrib.
365 */
366 EGLBoolean
367 _eglGetConfigAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config,
368 EGLint attribute, EGLint *value)
369 {
370 const _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
371 const EGLint k = attribute - FIRST_ATTRIB;
372 if (k >= 0 && k < MAX_ATTRIBS) {
373 *value = conf->Attrib[k];
374 return EGL_TRUE;
375 }
376 else {
377 _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
378 return EGL_FALSE;
379 }
380 }
381
382
383 /**
384 * Fallback for eglGetConfigs.
385 */
386 EGLBoolean
387 _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs,
388 EGLint config_size, EGLint *num_config)
389 {
390 _EGLDisplay *disp = _eglLookupDisplay(dpy);
391
392 if (!drv->Initialized) {
393 _eglError(EGL_NOT_INITIALIZED, "eglGetConfigs");
394 return EGL_FALSE;
395 }
396
397 if (configs) {
398 EGLint i;
399 *num_config = MIN2(disp->NumConfigs, config_size);
400 for (i = 0; i < *num_config; i++) {
401 configs[i] = disp->Configs[i]->Handle;
402 }
403 }
404 else {
405 /* just return total number of supported configs */
406 *num_config = disp->NumConfigs;
407 }
408
409 return EGL_TRUE;
410 }