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