sync with latest EGL_MESA_screen_surface spec (EGLScreenMESA handles)
[mesa.git] / src / egl / main / eglconfig.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <assert.h>
4 #include "eglconfig.h"
5 #include "egldisplay.h"
6 #include "egldriver.h"
7 #include "eglglobals.h"
8
9
10 #define MIN2(A, B) (((A) < (B)) ? (A) : (B))
11
12
13 /**
14 * Init the given _EGLconfig to default values.
15 * \param id the configuration's ID.
16 */
17 void
18 _eglInitConfig(_EGLConfig *config, EGLint id)
19 {
20 memset(config, 0, sizeof(*config));
21 config->Handle = id;
22 SET_CONFIG_ATTRIB(config, EGL_CONFIG_ID, id);
23 SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGB, EGL_DONT_CARE);
24 SET_CONFIG_ATTRIB(config, EGL_BIND_TO_TEXTURE_RGBA, EGL_DONT_CARE);
25 SET_CONFIG_ATTRIB(config, EGL_CONFIG_CAVEAT, EGL_DONT_CARE);
26 SET_CONFIG_ATTRIB(config, EGL_NATIVE_RENDERABLE, EGL_DONT_CARE);
27 SET_CONFIG_ATTRIB(config, EGL_NATIVE_VISUAL_TYPE, EGL_DONT_CARE);
28 SET_CONFIG_ATTRIB(config, EGL_MIN_SWAP_INTERVAL, EGL_DONT_CARE);
29 SET_CONFIG_ATTRIB(config, EGL_MAX_SWAP_INTERVAL, EGL_DONT_CARE);
30 SET_CONFIG_ATTRIB(config, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
31 SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_TYPE, EGL_NONE);
32 SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_RED_VALUE, EGL_DONT_CARE);
33 SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_GREEN_VALUE, EGL_DONT_CARE);
34 SET_CONFIG_ATTRIB(config, EGL_TRANSPARENT_BLUE_VALUE, EGL_DONT_CARE);
35 }
36
37
38 /**
39 * Given an EGLConfig handle, return the corresponding _EGLConfig object.
40 */
41 _EGLConfig *
42 _eglLookupConfig(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config)
43 {
44 EGLint i;
45 _EGLDisplay *disp = _eglLookupDisplay(dpy);
46 for (i = 0; i < disp->NumConfigs; i++) {
47 if (disp->Configs[i].Handle == config) {
48 return disp->Configs + i;
49 }
50 }
51 return NULL;
52 }
53
54
55 /**
56 * Add the given _EGLConifg to the given display.
57 */
58 _EGLConfig *
59 _eglAddConfig(_EGLDisplay *display, const _EGLConfig *config)
60 {
61 _EGLConfig *newConfigs;
62 EGLint n;
63
64 n = display->NumConfigs;
65
66 newConfigs = (_EGLConfig *) realloc(display->Configs,
67 (n + 1) * sizeof(_EGLConfig));
68 if (newConfigs) {
69 display->Configs = newConfigs;
70 display->Configs[n] = *config; /* copy struct */
71 display->NumConfigs++;
72 return display->Configs + n;
73 }
74 else {
75 return NULL;
76 }
77 }
78
79
80
81 /**
82 * Parse the attrib_list to fill in the fields of the given _egl_config
83 * Return EGL_FALSE if any errors, EGL_TRUE otherwise.
84 */
85 EGLBoolean
86 _eglParseConfigAttribs(_EGLConfig *config, const EGLint *attrib_list)
87 {
88 EGLint i;
89
90 /* XXX set all config attribs to EGL_DONT_CARE */
91
92 for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i++) {
93 EGLint k = attrib_list[i] - FIRST_ATTRIB;
94 if (k >= 0 && k < MAX_ATTRIBS) {
95 config->Attrib[k] = attrib_list[++i];
96 }
97 else {
98 _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
99 return EGL_FALSE;
100 }
101 }
102 return EGL_TRUE;
103 }
104
105
106 #define EXACT 1
107 #define ATLEAST 2
108 #define MASK 3
109 #define SMALLER 4
110 #define SPECIAL 5
111 #define NONE 6
112
113 struct sort_info {
114 EGLint Attribute;
115 EGLint MatchCriteria;
116 EGLint SortOrder;
117 };
118
119 /* This encodes the info from Table 3.5 of the EGL spec, ordered by
120 * Sort Priority.
121 */
122 static struct sort_info SortInfo[] = {
123 { EGL_CONFIG_CAVEAT, EXACT, SPECIAL },
124 { EGL_RED_SIZE, ATLEAST, SPECIAL },
125 { EGL_GREEN_SIZE, ATLEAST, SPECIAL },
126 { EGL_BLUE_SIZE, ATLEAST, SPECIAL },
127 { EGL_ALPHA_SIZE, ATLEAST, SPECIAL },
128 { EGL_BUFFER_SIZE, ATLEAST, SMALLER },
129 { EGL_SAMPLE_BUFFERS, ATLEAST, SMALLER },
130 { EGL_SAMPLES, ATLEAST, SMALLER },
131 { EGL_DEPTH_SIZE, ATLEAST, SMALLER },
132 { EGL_STENCIL_SIZE, ATLEAST, SMALLER },
133 { EGL_NATIVE_VISUAL_TYPE, EXACT, SPECIAL },
134 { EGL_CONFIG_ID, EXACT, SMALLER },
135 { EGL_BIND_TO_TEXTURE_RGB, EXACT, NONE },
136 { EGL_BIND_TO_TEXTURE_RGBA, EXACT, NONE },
137 { EGL_LEVEL, EXACT, NONE },
138 { EGL_NATIVE_RENDERABLE, EXACT, NONE },
139 { EGL_MAX_SWAP_INTERVAL, EXACT, NONE },
140 { EGL_MIN_SWAP_INTERVAL, EXACT, NONE },
141 { EGL_SURFACE_TYPE, MASK, NONE },
142 { EGL_TRANSPARENT_TYPE, EXACT, NONE },
143 { EGL_TRANSPARENT_RED_VALUE, EXACT, NONE },
144 { EGL_TRANSPARENT_GREEN_VALUE, EXACT, NONE },
145 { EGL_TRANSPARENT_BLUE_VALUE, EXACT, NONE },
146 { 0, 0, 0 }
147 };
148
149
150 /**
151 * Return EGL_TRUE if the attributes of c meet or exceed the minimums
152 * specified by min.
153 */
154 EGLBoolean
155 _eglConfigQualifies(const _EGLConfig *c, const _EGLConfig *min)
156 {
157 EGLint i;
158 for (i = 0; SortInfo[i].Attribute != 0; i++) {
159 const EGLint mv = GET_CONFIG_ATTRIB(min, SortInfo[i].Attribute);
160 if (mv != EGL_DONT_CARE) {
161 const EGLint cv = GET_CONFIG_ATTRIB(c, SortInfo[i].Attribute);
162 if (SortInfo[i].MatchCriteria == EXACT) {
163 if (cv != mv) {
164 return EGL_FALSE;
165 }
166 }
167 else if (SortInfo[i].MatchCriteria == ATLEAST) {
168 if (cv < mv) {
169 return EGL_FALSE;
170 }
171 }
172 else {
173 assert(SortInfo[i].MatchCriteria == MASK);
174 if ((mv & cv) != mv) {
175 return EGL_FALSE;
176 }
177 }
178 }
179 }
180 return EGL_TRUE;
181 }
182
183
184 /**
185 * Compare configs 'a' and 'b' and return -1 if a belongs before b,
186 * 1 if a belongs after b, or 0 if they're equal.
187 */
188 EGLint
189 _eglCompareConfigs(const _EGLConfig *a, const _EGLConfig *b)
190 {
191 EGLint i;
192 for (i = 0; SortInfo[i].Attribute != 0; i++) {
193 const EGLint av = GET_CONFIG_ATTRIB(a, SortInfo[i].Attribute);
194 const EGLint bv = GET_CONFIG_ATTRIB(b, SortInfo[i].Attribute);
195 if (SortInfo[i].SortOrder == SMALLER) {
196 if (av < bv)
197 return -1;
198 else if (av > bv)
199 return 1;
200 /* else, continue examining attribute values */
201 }
202 else if (SortInfo[i].SortOrder == SPECIAL) {
203 if (SortInfo[i].Attribute == EGL_CONFIG_CAVEAT) {
204 /* values are EGL_NONE, SLOW_CONFIG, or NON_CONFORMANT_CONFIG */
205 if (av < bv)
206 return -1;
207 else if (av > bv)
208 return 1;
209 }
210 else if (SortInfo[i].Attribute == EGL_RED_SIZE ||
211 SortInfo[i].Attribute == EGL_GREEN_SIZE ||
212 SortInfo[i].Attribute == EGL_BLUE_SIZE ||
213 SortInfo[i].Attribute == EGL_ALPHA_SIZE) {
214 if (av > bv)
215 return -1;
216 else if (av < bv)
217 return 1;
218 }
219 else {
220 assert(SortInfo[i].Attribute == EGL_NATIVE_VISUAL_TYPE);
221 if (av < bv)
222 return -1;
223 else if (av > bv)
224 return 1;
225 }
226 }
227 else {
228 assert(SortInfo[i].SortOrder == NONE);
229 /* continue examining attribute values */
230 }
231 }
232 return 0;
233 }
234
235
236 /**
237 * Typical fallback routine for eglChooseConfig
238 */
239 EGLBoolean
240 _eglChooseConfig(_EGLDriver *drv, EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
241 {
242 _EGLDisplay *disp = _eglLookupDisplay(dpy);
243 _EGLConfig criteria;
244 EGLint i;
245
246 /* parse the attrib_list to initialize criteria */
247 if (!_eglParseConfigAttribs(&criteria, attrib_list)) {
248 return EGL_FALSE;
249 }
250
251 *num_config = 0;
252 for (i = 0; i < disp->NumConfigs; i++) {
253 const _EGLConfig *conf = disp->Configs + i;
254 if (_eglConfigQualifies(conf, &criteria)) {
255 if (*num_config < config_size) {
256 /* save */
257 configs[*num_config] = conf->Handle;
258 (*num_config)++;
259 }
260 else {
261 break;
262 }
263 }
264 }
265
266 /* XXX sort the list here */
267
268 return EGL_TRUE;
269 }
270
271
272 /**
273 * Fallback for eglGetConfigAttrib.
274 */
275 EGLBoolean
276 _eglGetConfigAttrib(_EGLDriver *drv, EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
277 {
278 const _EGLConfig *conf = _eglLookupConfig(drv, dpy, config);
279 const EGLint k = attribute - FIRST_ATTRIB;
280 if (k >= 0 && k < MAX_ATTRIBS) {
281 *value = conf->Attrib[k];
282 return EGL_TRUE;
283 }
284 else {
285 _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
286 return EGL_FALSE;
287 }
288 }
289
290
291 /**
292 * Fallback for eglGetConfigs.
293 */
294 EGLBoolean
295 _eglGetConfigs(_EGLDriver *drv, EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
296 {
297 _EGLDisplay *disp = _eglLookupDisplay(dpy);
298
299 if (!drv->Initialized) {
300 _eglError(EGL_NOT_INITIALIZED, "eglGetConfigs");
301 return EGL_FALSE;
302 }
303
304 *num_config = MIN2(disp->NumConfigs, config_size);
305 if (configs) {
306 EGLint i;
307 for (i = 0; i < *num_config; i++) {
308 configs[i] = disp->Configs[i].Handle;
309 }
310 }
311 return EGL_TRUE;
312 }