eglconfig.c revision 2f2cf461c57974abd89e4917945cc8ae6a67a72e
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
20void
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 */
33void
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 */
62EGLConfig
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 */
125EGLBoolean
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
186struct 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 */
197static 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 */
229static 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 */
264static 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 */
320EGLBoolean
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 */
367EGLBoolean
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 */
386EGLBoolean
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}
404