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