eglconfig.c revision 848b8605
1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2008 VMware, Inc.
4848b8605Smrg * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com>
5848b8605Smrg * Copyright 2010-2011 LunarG, Inc.
6848b8605Smrg * All Rights Reserved.
7848b8605Smrg *
8848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9848b8605Smrg * copy of this software and associated documentation files (the
10848b8605Smrg * "Software"), to deal in the Software without restriction, including
11848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
12848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
13848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
14848b8605Smrg * the following conditions:
15848b8605Smrg *
16848b8605Smrg * The above copyright notice and this permission notice (including the
17848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
18848b8605Smrg * of the Software.
19848b8605Smrg *
20848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26848b8605Smrg * DEALINGS IN THE SOFTWARE.
27848b8605Smrg *
28848b8605Smrg **************************************************************************/
29848b8605Smrg
30848b8605Smrg
31848b8605Smrg/**
32848b8605Smrg * EGL Configuration (pixel format) functions.
33848b8605Smrg */
34848b8605Smrg
35848b8605Smrg
36848b8605Smrg#include <stdlib.h>
37848b8605Smrg#include <string.h>
38848b8605Smrg#include <assert.h>
39848b8605Smrg#include "eglconfig.h"
40848b8605Smrg#include "egldisplay.h"
41848b8605Smrg#include "eglcurrent.h"
42848b8605Smrg#include "egllog.h"
43848b8605Smrg
44848b8605Smrg
45848b8605Smrg#define MIN2(A, B)  (((A) < (B)) ? (A) : (B))
46848b8605Smrg
47848b8605Smrg
48848b8605Smrg/**
49848b8605Smrg * Init the given _EGLconfig to default values.
50848b8605Smrg * \param id  the configuration's ID.
51848b8605Smrg *
52848b8605Smrg * Note that id must be positive for the config to be valid.
53848b8605Smrg * It is also recommended that when there are N configs, their
54848b8605Smrg * IDs are from 1 to N respectively.
55848b8605Smrg */
56848b8605Smrgvoid
57848b8605Smrg_eglInitConfig(_EGLConfig *conf, _EGLDisplay *dpy, EGLint id)
58848b8605Smrg{
59848b8605Smrg   memset(conf, 0, sizeof(*conf));
60848b8605Smrg
61848b8605Smrg   conf->Display = dpy;
62848b8605Smrg
63848b8605Smrg   /* some attributes take non-zero default values */
64848b8605Smrg   conf->ConfigID = id;
65848b8605Smrg   conf->ConfigCaveat = EGL_NONE;
66848b8605Smrg   conf->TransparentType = EGL_NONE;
67848b8605Smrg   conf->NativeVisualType = EGL_NONE;
68848b8605Smrg   conf->ColorBufferType = EGL_RGB_BUFFER;
69848b8605Smrg}
70848b8605Smrg
71848b8605Smrg
72848b8605Smrg/**
73848b8605Smrg * Link a config to its display and return the handle of the link.
74848b8605Smrg * The handle can be passed to client directly.
75848b8605Smrg *
76848b8605Smrg * Note that we just save the ptr to the config (we don't copy the config).
77848b8605Smrg */
78848b8605SmrgPUBLIC EGLConfig
79848b8605Smrg_eglLinkConfig(_EGLConfig *conf)
80848b8605Smrg{
81848b8605Smrg   _EGLDisplay *dpy = conf->Display;
82848b8605Smrg
83848b8605Smrg   /* sanity check */
84848b8605Smrg   assert(dpy && conf->ConfigID > 0);
85848b8605Smrg
86848b8605Smrg   if (!dpy->Configs) {
87848b8605Smrg      dpy->Configs = _eglCreateArray("Config", 16);
88848b8605Smrg      if (!dpy->Configs)
89848b8605Smrg         return (EGLConfig) NULL;
90848b8605Smrg   }
91848b8605Smrg
92848b8605Smrg   _eglAppendArray(dpy->Configs, (void *) conf);
93848b8605Smrg
94848b8605Smrg   return (EGLConfig) conf;
95848b8605Smrg}
96848b8605Smrg
97848b8605Smrg
98848b8605Smrg/**
99848b8605Smrg * Lookup a handle to find the linked config.
100848b8605Smrg * Return NULL if the handle has no corresponding linked config.
101848b8605Smrg */
102848b8605Smrg_EGLConfig *
103848b8605Smrg_eglLookupConfig(EGLConfig config, _EGLDisplay *dpy)
104848b8605Smrg{
105848b8605Smrg   _EGLConfig *conf;
106848b8605Smrg
107848b8605Smrg   if (!dpy)
108848b8605Smrg      return NULL;
109848b8605Smrg
110848b8605Smrg   conf = (_EGLConfig *) _eglFindArray(dpy->Configs, (void *) config);
111848b8605Smrg   if (conf)
112848b8605Smrg      assert(conf->Display == dpy);
113848b8605Smrg
114848b8605Smrg   return conf;
115848b8605Smrg}
116848b8605Smrg
117848b8605Smrg
118848b8605Smrgenum {
119848b8605Smrg   /* types */
120848b8605Smrg   ATTRIB_TYPE_INTEGER,
121848b8605Smrg   ATTRIB_TYPE_BOOLEAN,
122848b8605Smrg   ATTRIB_TYPE_BITMASK,
123848b8605Smrg   ATTRIB_TYPE_ENUM,
124848b8605Smrg   ATTRIB_TYPE_PSEUDO, /* non-queryable */
125848b8605Smrg   ATTRIB_TYPE_PLATFORM, /* platform-dependent */
126848b8605Smrg   /* criteria */
127848b8605Smrg   ATTRIB_CRITERION_EXACT,
128848b8605Smrg   ATTRIB_CRITERION_ATLEAST,
129848b8605Smrg   ATTRIB_CRITERION_MASK,
130848b8605Smrg   ATTRIB_CRITERION_SPECIAL,
131848b8605Smrg   ATTRIB_CRITERION_IGNORE
132848b8605Smrg};
133848b8605Smrg
134848b8605Smrg
135848b8605Smrg/* EGL spec Table 3.1 and 3.4 */
136848b8605Smrgstatic const struct {
137848b8605Smrg   EGLint attr;
138848b8605Smrg   EGLint type;
139848b8605Smrg   EGLint criterion;
140848b8605Smrg   EGLint default_value;
141848b8605Smrg} _eglValidationTable[] =
142848b8605Smrg{
143848b8605Smrg   /* core */
144848b8605Smrg   { EGL_BUFFER_SIZE,               ATTRIB_TYPE_INTEGER,
145848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
146848b8605Smrg                                    0 },
147848b8605Smrg   { EGL_RED_SIZE,                  ATTRIB_TYPE_INTEGER,
148848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
149848b8605Smrg                                    0 },
150848b8605Smrg   { EGL_GREEN_SIZE,                ATTRIB_TYPE_INTEGER,
151848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
152848b8605Smrg                                    0 },
153848b8605Smrg   { EGL_BLUE_SIZE,                 ATTRIB_TYPE_INTEGER,
154848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
155848b8605Smrg                                    0 },
156848b8605Smrg   { EGL_LUMINANCE_SIZE,            ATTRIB_TYPE_INTEGER,
157848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
158848b8605Smrg                                    0 },
159848b8605Smrg   { EGL_ALPHA_SIZE,                ATTRIB_TYPE_INTEGER,
160848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
161848b8605Smrg                                    0 },
162848b8605Smrg   { EGL_ALPHA_MASK_SIZE,           ATTRIB_TYPE_INTEGER,
163848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
164848b8605Smrg                                    0 },
165848b8605Smrg   { EGL_BIND_TO_TEXTURE_RGB,       ATTRIB_TYPE_BOOLEAN,
166848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
167848b8605Smrg                                    EGL_DONT_CARE },
168848b8605Smrg   { EGL_BIND_TO_TEXTURE_RGBA,      ATTRIB_TYPE_BOOLEAN,
169848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
170848b8605Smrg                                    EGL_DONT_CARE },
171848b8605Smrg   { EGL_COLOR_BUFFER_TYPE,         ATTRIB_TYPE_ENUM,
172848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
173848b8605Smrg                                    EGL_RGB_BUFFER },
174848b8605Smrg   { EGL_CONFIG_CAVEAT,             ATTRIB_TYPE_ENUM,
175848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
176848b8605Smrg                                    EGL_DONT_CARE },
177848b8605Smrg   { EGL_CONFIG_ID,                 ATTRIB_TYPE_INTEGER,
178848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
179848b8605Smrg                                    EGL_DONT_CARE },
180848b8605Smrg   { EGL_CONFORMANT,                ATTRIB_TYPE_BITMASK,
181848b8605Smrg                                    ATTRIB_CRITERION_MASK,
182848b8605Smrg                                    0 },
183848b8605Smrg   { EGL_DEPTH_SIZE,                ATTRIB_TYPE_INTEGER,
184848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
185848b8605Smrg                                    0 },
186848b8605Smrg   { EGL_LEVEL,                     ATTRIB_TYPE_PLATFORM,
187848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
188848b8605Smrg                                    0 },
189848b8605Smrg   { EGL_MAX_PBUFFER_WIDTH,         ATTRIB_TYPE_INTEGER,
190848b8605Smrg                                    ATTRIB_CRITERION_IGNORE,
191848b8605Smrg                                    0 },
192848b8605Smrg   { EGL_MAX_PBUFFER_HEIGHT,        ATTRIB_TYPE_INTEGER,
193848b8605Smrg                                    ATTRIB_CRITERION_IGNORE,
194848b8605Smrg                                    0 },
195848b8605Smrg   { EGL_MAX_PBUFFER_PIXELS,        ATTRIB_TYPE_INTEGER,
196848b8605Smrg                                    ATTRIB_CRITERION_IGNORE,
197848b8605Smrg                                    0 },
198848b8605Smrg   { EGL_MAX_SWAP_INTERVAL,         ATTRIB_TYPE_INTEGER,
199848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
200848b8605Smrg                                    EGL_DONT_CARE },
201848b8605Smrg   { EGL_MIN_SWAP_INTERVAL,         ATTRIB_TYPE_INTEGER,
202848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
203848b8605Smrg                                    EGL_DONT_CARE },
204848b8605Smrg   { EGL_NATIVE_RENDERABLE,         ATTRIB_TYPE_BOOLEAN,
205848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
206848b8605Smrg                                    EGL_DONT_CARE },
207848b8605Smrg   { EGL_NATIVE_VISUAL_ID,          ATTRIB_TYPE_PLATFORM,
208848b8605Smrg                                    ATTRIB_CRITERION_IGNORE,
209848b8605Smrg                                    0 },
210848b8605Smrg   { EGL_NATIVE_VISUAL_TYPE,        ATTRIB_TYPE_PLATFORM,
211848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
212848b8605Smrg                                    EGL_DONT_CARE },
213848b8605Smrg   { EGL_RENDERABLE_TYPE,           ATTRIB_TYPE_BITMASK,
214848b8605Smrg                                    ATTRIB_CRITERION_MASK,
215848b8605Smrg                                    EGL_OPENGL_ES_BIT },
216848b8605Smrg   { EGL_SAMPLE_BUFFERS,            ATTRIB_TYPE_INTEGER,
217848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
218848b8605Smrg                                    0 },
219848b8605Smrg   { EGL_SAMPLES,                   ATTRIB_TYPE_INTEGER,
220848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
221848b8605Smrg                                    0 },
222848b8605Smrg   { EGL_STENCIL_SIZE,              ATTRIB_TYPE_INTEGER,
223848b8605Smrg                                    ATTRIB_CRITERION_ATLEAST,
224848b8605Smrg                                    0 },
225848b8605Smrg   { EGL_SURFACE_TYPE,              ATTRIB_TYPE_BITMASK,
226848b8605Smrg                                    ATTRIB_CRITERION_MASK,
227848b8605Smrg                                    EGL_WINDOW_BIT },
228848b8605Smrg   { EGL_TRANSPARENT_TYPE,          ATTRIB_TYPE_ENUM,
229848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
230848b8605Smrg                                    EGL_NONE },
231848b8605Smrg   { EGL_TRANSPARENT_RED_VALUE,     ATTRIB_TYPE_INTEGER,
232848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
233848b8605Smrg                                    EGL_DONT_CARE },
234848b8605Smrg   { EGL_TRANSPARENT_GREEN_VALUE,   ATTRIB_TYPE_INTEGER,
235848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
236848b8605Smrg                                    EGL_DONT_CARE },
237848b8605Smrg   { EGL_TRANSPARENT_BLUE_VALUE,    ATTRIB_TYPE_INTEGER,
238848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
239848b8605Smrg                                    EGL_DONT_CARE },
240848b8605Smrg   { EGL_MATCH_NATIVE_PIXMAP,       ATTRIB_TYPE_PSEUDO,
241848b8605Smrg                                    ATTRIB_CRITERION_SPECIAL,
242848b8605Smrg                                    EGL_NONE },
243848b8605Smrg   /* extensions */
244848b8605Smrg   { EGL_Y_INVERTED_NOK,            ATTRIB_TYPE_BOOLEAN,
245848b8605Smrg                                    ATTRIB_CRITERION_EXACT,
246848b8605Smrg                                    EGL_DONT_CARE }
247848b8605Smrg};
248848b8605Smrg
249848b8605Smrg
250848b8605Smrg/**
251848b8605Smrg * Return true if a config is valid.  When for_matching is true,
252848b8605Smrg * EGL_DONT_CARE is accepted as a valid attribute value, and checks
253848b8605Smrg * for conflicting attribute values are skipped.
254848b8605Smrg *
255848b8605Smrg * Note that some attributes are platform-dependent and are not
256848b8605Smrg * checked.
257848b8605Smrg */
258848b8605SmrgEGLBoolean
259848b8605Smrg_eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching)
260848b8605Smrg{
261848b8605Smrg   EGLint i, attr, val;
262848b8605Smrg   EGLBoolean valid = EGL_TRUE;
263848b8605Smrg
264848b8605Smrg   /* check attributes by their types */
265848b8605Smrg   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
266848b8605Smrg      EGLint mask;
267848b8605Smrg
268848b8605Smrg      attr = _eglValidationTable[i].attr;
269848b8605Smrg      val = _eglGetConfigKey(conf, attr);
270848b8605Smrg
271848b8605Smrg      switch (_eglValidationTable[i].type) {
272848b8605Smrg      case ATTRIB_TYPE_INTEGER:
273848b8605Smrg         switch (attr) {
274848b8605Smrg         case EGL_CONFIG_ID:
275848b8605Smrg            /* config id must be positive */
276848b8605Smrg            if (val <= 0)
277848b8605Smrg               valid = EGL_FALSE;
278848b8605Smrg            break;
279848b8605Smrg         case EGL_SAMPLE_BUFFERS:
280848b8605Smrg            /* there can be at most 1 sample buffer */
281848b8605Smrg            if (val > 1 || val < 0)
282848b8605Smrg               valid = EGL_FALSE;
283848b8605Smrg            break;
284848b8605Smrg         default:
285848b8605Smrg            if (val < 0)
286848b8605Smrg               valid = EGL_FALSE;
287848b8605Smrg            break;
288848b8605Smrg         }
289848b8605Smrg         break;
290848b8605Smrg      case ATTRIB_TYPE_BOOLEAN:
291848b8605Smrg         if (val != EGL_TRUE && val != EGL_FALSE)
292848b8605Smrg            valid = EGL_FALSE;
293848b8605Smrg         break;
294848b8605Smrg      case ATTRIB_TYPE_ENUM:
295848b8605Smrg         switch (attr) {
296848b8605Smrg         case EGL_CONFIG_CAVEAT:
297848b8605Smrg            if (val != EGL_NONE && val != EGL_SLOW_CONFIG &&
298848b8605Smrg                val != EGL_NON_CONFORMANT_CONFIG)
299848b8605Smrg               valid = EGL_FALSE;
300848b8605Smrg            break;
301848b8605Smrg         case EGL_TRANSPARENT_TYPE:
302848b8605Smrg            if (val != EGL_NONE && val != EGL_TRANSPARENT_RGB)
303848b8605Smrg               valid = EGL_FALSE;
304848b8605Smrg            break;
305848b8605Smrg         case EGL_COLOR_BUFFER_TYPE:
306848b8605Smrg            if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER)
307848b8605Smrg               valid = EGL_FALSE;
308848b8605Smrg            break;
309848b8605Smrg         default:
310848b8605Smrg            assert(0);
311848b8605Smrg            break;
312848b8605Smrg         }
313848b8605Smrg         break;
314848b8605Smrg      case ATTRIB_TYPE_BITMASK:
315848b8605Smrg         switch (attr) {
316848b8605Smrg         case EGL_SURFACE_TYPE:
317848b8605Smrg            mask = EGL_PBUFFER_BIT |
318848b8605Smrg                   EGL_PIXMAP_BIT |
319848b8605Smrg                   EGL_WINDOW_BIT |
320848b8605Smrg                   EGL_VG_COLORSPACE_LINEAR_BIT |
321848b8605Smrg                   EGL_VG_ALPHA_FORMAT_PRE_BIT |
322848b8605Smrg                   EGL_MULTISAMPLE_RESOLVE_BOX_BIT |
323848b8605Smrg                   EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
324848b8605Smrg#ifdef EGL_MESA_screen_surface
325848b8605Smrg            if (conf->Display->Extensions.MESA_screen_surface)
326848b8605Smrg               mask |= EGL_SCREEN_BIT_MESA;
327848b8605Smrg#endif
328848b8605Smrg            break;
329848b8605Smrg         case EGL_RENDERABLE_TYPE:
330848b8605Smrg         case EGL_CONFORMANT:
331848b8605Smrg            mask = EGL_OPENGL_ES_BIT |
332848b8605Smrg                   EGL_OPENVG_BIT |
333848b8605Smrg                   EGL_OPENGL_ES2_BIT |
334848b8605Smrg                   EGL_OPENGL_ES3_BIT_KHR |
335848b8605Smrg                   EGL_OPENGL_BIT;
336848b8605Smrg            break;
337848b8605Smrg         default:
338848b8605Smrg            assert(0);
339848b8605Smrg            mask = 0;
340848b8605Smrg            break;
341848b8605Smrg         }
342848b8605Smrg         if (val & ~mask)
343848b8605Smrg            valid = EGL_FALSE;
344848b8605Smrg         break;
345848b8605Smrg      case ATTRIB_TYPE_PLATFORM:
346848b8605Smrg         /* unable to check platform-dependent attributes here */
347848b8605Smrg         break;
348848b8605Smrg      case ATTRIB_TYPE_PSEUDO:
349848b8605Smrg         /* pseudo attributes should not be set */
350848b8605Smrg         if (val != 0)
351848b8605Smrg            valid = EGL_FALSE;
352848b8605Smrg         break;
353848b8605Smrg      default:
354848b8605Smrg         assert(0);
355848b8605Smrg         break;
356848b8605Smrg      }
357848b8605Smrg
358848b8605Smrg      if (!valid && for_matching) {
359848b8605Smrg         /* accept EGL_DONT_CARE as a valid value */
360848b8605Smrg         if (val == EGL_DONT_CARE)
361848b8605Smrg            valid = EGL_TRUE;
362848b8605Smrg         if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_SPECIAL)
363848b8605Smrg            valid = EGL_TRUE;
364848b8605Smrg      }
365848b8605Smrg      if (!valid) {
366848b8605Smrg         _eglLog(_EGL_DEBUG,
367848b8605Smrg               "attribute 0x%04x has an invalid value 0x%x", attr, val);
368848b8605Smrg         break;
369848b8605Smrg      }
370848b8605Smrg   }
371848b8605Smrg
372848b8605Smrg   /* any invalid attribute value should have been catched */
373848b8605Smrg   if (!valid || for_matching)
374848b8605Smrg      return valid;
375848b8605Smrg
376848b8605Smrg   /* now check for conflicting attribute values */
377848b8605Smrg
378848b8605Smrg   switch (conf->ColorBufferType) {
379848b8605Smrg   case EGL_RGB_BUFFER:
380848b8605Smrg      if (conf->LuminanceSize)
381848b8605Smrg         valid = EGL_FALSE;
382848b8605Smrg      if (conf->RedSize + conf->GreenSize +
383848b8605Smrg            conf->BlueSize + conf->AlphaSize != conf->BufferSize)
384848b8605Smrg         valid = EGL_FALSE;
385848b8605Smrg      break;
386848b8605Smrg   case EGL_LUMINANCE_BUFFER:
387848b8605Smrg      if (conf->RedSize || conf->GreenSize || conf->BlueSize)
388848b8605Smrg         valid = EGL_FALSE;
389848b8605Smrg      if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize)
390848b8605Smrg         valid = EGL_FALSE;
391848b8605Smrg      break;
392848b8605Smrg   }
393848b8605Smrg   if (!valid) {
394848b8605Smrg      _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes");
395848b8605Smrg      return EGL_FALSE;
396848b8605Smrg   }
397848b8605Smrg
398848b8605Smrg   if (!conf->SampleBuffers && conf->Samples)
399848b8605Smrg      valid = EGL_FALSE;
400848b8605Smrg   if (!valid) {
401848b8605Smrg      _eglLog(_EGL_DEBUG, "conflicting samples and sample buffers");
402848b8605Smrg      return EGL_FALSE;
403848b8605Smrg   }
404848b8605Smrg
405848b8605Smrg   if (!(conf->SurfaceType & EGL_WINDOW_BIT)) {
406848b8605Smrg      if (conf->NativeVisualID != 0 || conf->NativeVisualType != EGL_NONE)
407848b8605Smrg         valid = EGL_FALSE;
408848b8605Smrg   }
409848b8605Smrg   if (!(conf->SurfaceType & EGL_PBUFFER_BIT)) {
410848b8605Smrg      if (conf->BindToTextureRGB || conf->BindToTextureRGBA)
411848b8605Smrg         valid = EGL_FALSE;
412848b8605Smrg   }
413848b8605Smrg   if (!valid) {
414848b8605Smrg      _eglLog(_EGL_DEBUG, "conflicting surface type and native visual/texture binding");
415848b8605Smrg      return EGL_FALSE;
416848b8605Smrg   }
417848b8605Smrg
418848b8605Smrg   return valid;
419848b8605Smrg}
420848b8605Smrg
421848b8605Smrg
422848b8605Smrg/**
423848b8605Smrg * Return true if a config matches the criteria.  This and
424848b8605Smrg * _eglParseConfigAttribList together implement the algorithm
425848b8605Smrg * described in "Selection of EGLConfigs".
426848b8605Smrg *
427848b8605Smrg * Note that attributes that are special (currently, only
428848b8605Smrg * EGL_MATCH_NATIVE_PIXMAP) are ignored.
429848b8605Smrg */
430848b8605SmrgEGLBoolean
431848b8605Smrg_eglMatchConfig(const _EGLConfig *conf, const _EGLConfig *criteria)
432848b8605Smrg{
433848b8605Smrg   EGLint attr, val, i;
434848b8605Smrg   EGLBoolean matched = EGL_TRUE;
435848b8605Smrg
436848b8605Smrg   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
437848b8605Smrg      EGLint cmp;
438848b8605Smrg      if (_eglValidationTable[i].criterion == ATTRIB_CRITERION_IGNORE)
439848b8605Smrg         continue;
440848b8605Smrg
441848b8605Smrg      attr = _eglValidationTable[i].attr;
442848b8605Smrg      cmp = _eglGetConfigKey(criteria, attr);
443848b8605Smrg      if (cmp == EGL_DONT_CARE)
444848b8605Smrg         continue;
445848b8605Smrg
446848b8605Smrg      val = _eglGetConfigKey(conf, attr);
447848b8605Smrg      switch (_eglValidationTable[i].criterion) {
448848b8605Smrg      case ATTRIB_CRITERION_EXACT:
449848b8605Smrg         if (val != cmp)
450848b8605Smrg            matched = EGL_FALSE;
451848b8605Smrg         break;
452848b8605Smrg      case ATTRIB_CRITERION_ATLEAST:
453848b8605Smrg         if (val < cmp)
454848b8605Smrg            matched = EGL_FALSE;
455848b8605Smrg         break;
456848b8605Smrg      case ATTRIB_CRITERION_MASK:
457848b8605Smrg         if ((val & cmp) != cmp)
458848b8605Smrg            matched = EGL_FALSE;
459848b8605Smrg         break;
460848b8605Smrg      case ATTRIB_CRITERION_SPECIAL:
461848b8605Smrg         /* ignored here */
462848b8605Smrg         break;
463848b8605Smrg      default:
464848b8605Smrg         assert(0);
465848b8605Smrg         break;
466848b8605Smrg      }
467848b8605Smrg
468848b8605Smrg      if (!matched) {
469848b8605Smrg#ifndef DEBUG
470848b8605Smrg         /* only print the common errors when DEBUG is not defined */
471848b8605Smrg         if (attr != EGL_RENDERABLE_TYPE)
472848b8605Smrg            break;
473848b8605Smrg#endif
474848b8605Smrg         _eglLog(_EGL_DEBUG,
475848b8605Smrg               "the value (0x%x) of attribute 0x%04x did not meet the criteria (0x%x)",
476848b8605Smrg               val, attr, cmp);
477848b8605Smrg         break;
478848b8605Smrg      }
479848b8605Smrg   }
480848b8605Smrg
481848b8605Smrg   return matched;
482848b8605Smrg}
483848b8605Smrg
484848b8605Smrgstatic INLINE EGLBoolean
485848b8605Smrg_eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr)
486848b8605Smrg{
487848b8605Smrg   if (_eglOffsetOfConfig(attr) < 0)
488848b8605Smrg      return EGL_FALSE;
489848b8605Smrg
490848b8605Smrg   switch (attr) {
491848b8605Smrg   case EGL_Y_INVERTED_NOK:
492848b8605Smrg      return conf->Display->Extensions.NOK_texture_from_pixmap;
493848b8605Smrg   default:
494848b8605Smrg      break;
495848b8605Smrg   }
496848b8605Smrg
497848b8605Smrg   return EGL_TRUE;
498848b8605Smrg}
499848b8605Smrg
500848b8605Smrg/**
501848b8605Smrg * Initialize a criteria config from the given attribute list.
502848b8605Smrg * Return EGL_FALSE if any of the attribute is invalid.
503848b8605Smrg */
504848b8605SmrgEGLBoolean
505848b8605Smrg_eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *dpy,
506848b8605Smrg                          const EGLint *attrib_list)
507848b8605Smrg{
508848b8605Smrg   EGLint attr, val, i;
509848b8605Smrg
510848b8605Smrg   _eglInitConfig(conf, dpy, EGL_DONT_CARE);
511848b8605Smrg
512848b8605Smrg   /* reset to default values */
513848b8605Smrg   for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
514848b8605Smrg      attr = _eglValidationTable[i].attr;
515848b8605Smrg      val = _eglValidationTable[i].default_value;
516848b8605Smrg      _eglSetConfigKey(conf, attr, val);
517848b8605Smrg   }
518848b8605Smrg
519848b8605Smrg   /* parse the list */
520848b8605Smrg   for (i = 0; attrib_list && attrib_list[i] != EGL_NONE; i += 2) {
521848b8605Smrg      attr = attrib_list[i];
522848b8605Smrg      val = attrib_list[i + 1];
523848b8605Smrg
524848b8605Smrg      if (!_eglIsConfigAttribValid(conf, attr))
525848b8605Smrg	 return EGL_FALSE;
526848b8605Smrg
527848b8605Smrg      _eglSetConfigKey(conf, attr, val);
528848b8605Smrg   }
529848b8605Smrg
530848b8605Smrg   if (!_eglValidateConfig(conf, EGL_TRUE))
531848b8605Smrg      return EGL_FALSE;
532848b8605Smrg
533848b8605Smrg   /* EGL_LEVEL and EGL_MATCH_NATIVE_PIXMAP cannot be EGL_DONT_CARE */
534848b8605Smrg   if (conf->Level == EGL_DONT_CARE ||
535848b8605Smrg       conf->MatchNativePixmap == EGL_DONT_CARE)
536848b8605Smrg      return EGL_FALSE;
537848b8605Smrg
538848b8605Smrg   /* ignore other attributes when EGL_CONFIG_ID is given */
539848b8605Smrg   if (conf->ConfigID != EGL_DONT_CARE) {
540848b8605Smrg      for (i = 0; i < ARRAY_SIZE(_eglValidationTable); i++) {
541848b8605Smrg         attr = _eglValidationTable[i].attr;
542848b8605Smrg         if (attr != EGL_CONFIG_ID)
543848b8605Smrg            _eglSetConfigKey(conf, attr, EGL_DONT_CARE);
544848b8605Smrg      }
545848b8605Smrg   }
546848b8605Smrg   else {
547848b8605Smrg      if (!(conf->SurfaceType & EGL_WINDOW_BIT))
548848b8605Smrg         conf->NativeVisualType = EGL_DONT_CARE;
549848b8605Smrg
550848b8605Smrg      if (conf->TransparentType == EGL_NONE) {
551848b8605Smrg         conf->TransparentRedValue = EGL_DONT_CARE;
552848b8605Smrg         conf->TransparentGreenValue = EGL_DONT_CARE;
553848b8605Smrg         conf->TransparentBlueValue = EGL_DONT_CARE;
554848b8605Smrg      }
555848b8605Smrg   }
556848b8605Smrg
557848b8605Smrg   return EGL_TRUE;
558848b8605Smrg}
559848b8605Smrg
560848b8605Smrg
561848b8605Smrg/**
562848b8605Smrg * Decide the ordering of conf1 and conf2, under the given criteria.
563848b8605Smrg * When compare_id is true, this implements the algorithm described
564848b8605Smrg * in "Sorting of EGLConfigs".  When compare_id is false,
565848b8605Smrg * EGL_CONFIG_ID is not compared.
566848b8605Smrg *
567848b8605Smrg * It returns a negative integer if conf1 is considered to come
568848b8605Smrg * before conf2;  a positive integer if conf2 is considered to come
569848b8605Smrg * before conf1;  zero if the ordering cannot be decided.
570848b8605Smrg *
571848b8605Smrg * Note that EGL_NATIVE_VISUAL_TYPE is platform-dependent and is
572848b8605Smrg * ignored here.
573848b8605Smrg */
574848b8605SmrgEGLint
575848b8605Smrg_eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2,
576848b8605Smrg                   const _EGLConfig *criteria, EGLBoolean compare_id)
577848b8605Smrg{
578848b8605Smrg   const EGLint compare_attribs[] = {
579848b8605Smrg      EGL_BUFFER_SIZE,
580848b8605Smrg      EGL_SAMPLE_BUFFERS,
581848b8605Smrg      EGL_SAMPLES,
582848b8605Smrg      EGL_DEPTH_SIZE,
583848b8605Smrg      EGL_STENCIL_SIZE,
584848b8605Smrg      EGL_ALPHA_MASK_SIZE,
585848b8605Smrg   };
586848b8605Smrg   EGLint val1, val2;
587848b8605Smrg   EGLint i;
588848b8605Smrg
589848b8605Smrg   if (conf1 == conf2)
590848b8605Smrg      return 0;
591848b8605Smrg
592848b8605Smrg   /* the enum values have the desired ordering */
593848b8605Smrg   assert(EGL_NONE < EGL_SLOW_CONFIG);
594848b8605Smrg   assert(EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
595848b8605Smrg   val1 = conf1->ConfigCaveat - conf2->ConfigCaveat;
596848b8605Smrg   if (val1)
597848b8605Smrg      return val1;
598848b8605Smrg
599848b8605Smrg   /* the enum values have the desired ordering */
600848b8605Smrg   assert(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
601848b8605Smrg   val1 = conf1->ColorBufferType - conf2->ColorBufferType;
602848b8605Smrg   if (val1)
603848b8605Smrg      return val1;
604848b8605Smrg
605848b8605Smrg   if (criteria) {
606848b8605Smrg      val1 = val2 = 0;
607848b8605Smrg      if (conf1->ColorBufferType == EGL_RGB_BUFFER) {
608848b8605Smrg         if (criteria->RedSize > 0) {
609848b8605Smrg            val1 += conf1->RedSize;
610848b8605Smrg            val2 += conf2->RedSize;
611848b8605Smrg         }
612848b8605Smrg         if (criteria->GreenSize > 0) {
613848b8605Smrg            val1 += conf1->GreenSize;
614848b8605Smrg            val2 += conf2->GreenSize;
615848b8605Smrg         }
616848b8605Smrg         if (criteria->BlueSize > 0) {
617848b8605Smrg            val1 += conf1->BlueSize;
618848b8605Smrg            val2 += conf2->BlueSize;
619848b8605Smrg         }
620848b8605Smrg      }
621848b8605Smrg      else {
622848b8605Smrg         if (criteria->LuminanceSize > 0) {
623848b8605Smrg            val1 += conf1->LuminanceSize;
624848b8605Smrg            val2 += conf2->LuminanceSize;
625848b8605Smrg         }
626848b8605Smrg      }
627848b8605Smrg      if (criteria->AlphaSize > 0) {
628848b8605Smrg         val1 += conf1->AlphaSize;
629848b8605Smrg         val2 += conf2->AlphaSize;
630848b8605Smrg      }
631848b8605Smrg   }
632848b8605Smrg   else {
633848b8605Smrg      /* assume the default criteria, which gives no specific ordering */
634848b8605Smrg      val1 = val2 = 0;
635848b8605Smrg   }
636848b8605Smrg
637848b8605Smrg   /* for color bits, larger one is preferred */
638848b8605Smrg   if (val1 != val2)
639848b8605Smrg      return (val2 - val1);
640848b8605Smrg
641848b8605Smrg   for (i = 0; i < ARRAY_SIZE(compare_attribs); i++) {
642848b8605Smrg      val1 = _eglGetConfigKey(conf1, compare_attribs[i]);
643848b8605Smrg      val2 = _eglGetConfigKey(conf2, compare_attribs[i]);
644848b8605Smrg      if (val1 != val2)
645848b8605Smrg         return (val1 - val2);
646848b8605Smrg   }
647848b8605Smrg
648848b8605Smrg   /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */
649848b8605Smrg
650848b8605Smrg   return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0;
651848b8605Smrg}
652848b8605Smrg
653848b8605Smrg
654848b8605Smrgstatic INLINE
655848b8605Smrgvoid _eglSwapConfigs(const _EGLConfig **conf1, const _EGLConfig **conf2)
656848b8605Smrg{
657848b8605Smrg   const _EGLConfig *tmp = *conf1;
658848b8605Smrg   *conf1 = *conf2;
659848b8605Smrg   *conf2 = tmp;
660848b8605Smrg}
661848b8605Smrg
662848b8605Smrg
663848b8605Smrg/**
664848b8605Smrg * Quick sort an array of configs.  This differs from the standard
665848b8605Smrg * qsort() in that the compare function accepts an additional
666848b8605Smrg * argument.
667848b8605Smrg */
668848b8605Smrgstatic void
669848b8605Smrg_eglSortConfigs(const _EGLConfig **configs, EGLint count,
670848b8605Smrg                EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
671848b8605Smrg                                  void *),
672848b8605Smrg                void *priv_data)
673848b8605Smrg{
674848b8605Smrg   const EGLint pivot = 0;
675848b8605Smrg   EGLint i, j;
676848b8605Smrg
677848b8605Smrg   if (count <= 1)
678848b8605Smrg      return;
679848b8605Smrg
680848b8605Smrg   _eglSwapConfigs(&configs[pivot], &configs[count / 2]);
681848b8605Smrg   i = 1;
682848b8605Smrg   j = count - 1;
683848b8605Smrg   do {
684848b8605Smrg      while (i < count && compare(configs[i], configs[pivot], priv_data) < 0)
685848b8605Smrg         i++;
686848b8605Smrg      while (compare(configs[j], configs[pivot], priv_data) > 0)
687848b8605Smrg         j--;
688848b8605Smrg      if (i < j) {
689848b8605Smrg         _eglSwapConfigs(&configs[i], &configs[j]);
690848b8605Smrg         i++;
691848b8605Smrg         j--;
692848b8605Smrg      }
693848b8605Smrg      else if (i == j) {
694848b8605Smrg         i++;
695848b8605Smrg         j--;
696848b8605Smrg         break;
697848b8605Smrg      }
698848b8605Smrg   } while (i <= j);
699848b8605Smrg   _eglSwapConfigs(&configs[pivot], &configs[j]);
700848b8605Smrg
701848b8605Smrg   _eglSortConfigs(configs, j, compare, priv_data);
702848b8605Smrg   _eglSortConfigs(configs + i, count - i, compare, priv_data);
703848b8605Smrg}
704848b8605Smrg
705848b8605Smrg
706848b8605Smrg/**
707848b8605Smrg * A helper function for implementing eglChooseConfig.  See _eglFilterArray and
708848b8605Smrg * _eglSortConfigs for the meanings of match and compare.
709848b8605Smrg */
710848b8605SmrgEGLBoolean
711848b8605Smrg_eglFilterConfigArray(_EGLArray *array, EGLConfig *configs,
712848b8605Smrg                      EGLint config_size, EGLint *num_configs,
713848b8605Smrg                      EGLBoolean (*match)(const _EGLConfig *, void *),
714848b8605Smrg                      EGLint (*compare)(const _EGLConfig *, const _EGLConfig *,
715848b8605Smrg                                        void *),
716848b8605Smrg                      void *priv_data)
717848b8605Smrg{
718848b8605Smrg   _EGLConfig **configList;
719848b8605Smrg   EGLint i, count;
720848b8605Smrg
721848b8605Smrg   if (!num_configs)
722848b8605Smrg      return _eglError(EGL_BAD_PARAMETER, "eglChooseConfigs");
723848b8605Smrg
724848b8605Smrg   /* get the number of matched configs */
725848b8605Smrg   count = _eglFilterArray(array, NULL, 0,
726848b8605Smrg         (_EGLArrayForEach) match, priv_data);
727848b8605Smrg   if (!count) {
728848b8605Smrg      *num_configs = count;
729848b8605Smrg      return EGL_TRUE;
730848b8605Smrg   }
731848b8605Smrg
732848b8605Smrg   configList = malloc(sizeof(*configList) * count);
733848b8605Smrg   if (!configList)
734848b8605Smrg      return _eglError(EGL_BAD_ALLOC, "eglChooseConfig(out of memory)");
735848b8605Smrg
736848b8605Smrg   /* get the matched configs */
737848b8605Smrg   _eglFilterArray(array, (void **) configList, count,
738848b8605Smrg         (_EGLArrayForEach) match, priv_data);
739848b8605Smrg
740848b8605Smrg   /* perform sorting of configs */
741848b8605Smrg   if (configs && count) {
742848b8605Smrg      _eglSortConfigs((const _EGLConfig **) configList, count,
743848b8605Smrg                      compare, priv_data);
744848b8605Smrg      count = MIN2(count, config_size);
745848b8605Smrg      for (i = 0; i < count; i++)
746848b8605Smrg         configs[i] = _eglGetConfigHandle(configList[i]);
747848b8605Smrg   }
748848b8605Smrg
749848b8605Smrg   free(configList);
750848b8605Smrg
751848b8605Smrg   *num_configs = count;
752848b8605Smrg
753848b8605Smrg   return EGL_TRUE;
754848b8605Smrg}
755848b8605Smrg
756848b8605Smrg
757848b8605Smrgstatic EGLBoolean
758848b8605Smrg_eglFallbackMatch(const _EGLConfig *conf, void *priv_data)
759848b8605Smrg{
760848b8605Smrg   return _eglMatchConfig(conf, (const _EGLConfig *) priv_data);
761848b8605Smrg}
762848b8605Smrg
763848b8605Smrg
764848b8605Smrgstatic EGLint
765848b8605Smrg_eglFallbackCompare(const _EGLConfig *conf1, const _EGLConfig *conf2,
766848b8605Smrg                    void *priv_data)
767848b8605Smrg{
768848b8605Smrg   return _eglCompareConfigs(conf1, conf2,
769848b8605Smrg         (const _EGLConfig *) priv_data, EGL_TRUE);
770848b8605Smrg}
771848b8605Smrg
772848b8605Smrg
773848b8605Smrg/**
774848b8605Smrg * Typical fallback routine for eglChooseConfig
775848b8605Smrg */
776848b8605SmrgEGLBoolean
777848b8605Smrg_eglChooseConfig(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attrib_list,
778848b8605Smrg                 EGLConfig *configs, EGLint config_size, EGLint *num_configs)
779848b8605Smrg{
780848b8605Smrg   _EGLConfig criteria;
781848b8605Smrg
782848b8605Smrg   if (!_eglParseConfigAttribList(&criteria, disp, attrib_list))
783848b8605Smrg      return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig");
784848b8605Smrg
785848b8605Smrg   return _eglFilterConfigArray(disp->Configs,
786848b8605Smrg         configs, config_size, num_configs,
787848b8605Smrg         _eglFallbackMatch, _eglFallbackCompare,
788848b8605Smrg         (void *) &criteria);
789848b8605Smrg}
790848b8605Smrg
791848b8605Smrg
792848b8605Smrg/**
793848b8605Smrg * Fallback for eglGetConfigAttrib.
794848b8605Smrg */
795848b8605SmrgEGLBoolean
796848b8605Smrg_eglGetConfigAttrib(_EGLDriver *drv, _EGLDisplay *dpy, _EGLConfig *conf,
797848b8605Smrg                    EGLint attribute, EGLint *value)
798848b8605Smrg{
799848b8605Smrg   if (!_eglIsConfigAttribValid(conf, attribute))
800848b8605Smrg      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
801848b8605Smrg
802848b8605Smrg   /* nonqueryable attributes */
803848b8605Smrg   switch (attribute) {
804848b8605Smrg   case EGL_MATCH_NATIVE_PIXMAP:
805848b8605Smrg      return _eglError(EGL_BAD_ATTRIBUTE, "eglGetConfigAttrib");
806848b8605Smrg      break;
807848b8605Smrg   default:
808848b8605Smrg      break;
809848b8605Smrg   }
810848b8605Smrg
811848b8605Smrg   if (!value)
812848b8605Smrg      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigAttrib");
813848b8605Smrg
814848b8605Smrg   *value = _eglGetConfigKey(conf, attribute);
815848b8605Smrg   return EGL_TRUE;
816848b8605Smrg}
817848b8605Smrg
818848b8605Smrg
819848b8605Smrgstatic EGLBoolean
820848b8605Smrg_eglFlattenConfig(void *elem, void *buffer)
821848b8605Smrg{
822848b8605Smrg   _EGLConfig *conf = (_EGLConfig *) elem;
823848b8605Smrg   EGLConfig *handle = (EGLConfig *) buffer;
824848b8605Smrg   *handle = _eglGetConfigHandle(conf);
825848b8605Smrg   return EGL_TRUE;
826848b8605Smrg}
827848b8605Smrg
828848b8605Smrg/**
829848b8605Smrg * Fallback for eglGetConfigs.
830848b8605Smrg */
831848b8605SmrgEGLBoolean
832848b8605Smrg_eglGetConfigs(_EGLDriver *drv, _EGLDisplay *disp, EGLConfig *configs,
833848b8605Smrg               EGLint config_size, EGLint *num_config)
834848b8605Smrg{
835848b8605Smrg   if (!num_config)
836848b8605Smrg      return _eglError(EGL_BAD_PARAMETER, "eglGetConfigs");
837848b8605Smrg
838848b8605Smrg   *num_config = _eglFlattenArray(disp->Configs, (void *) configs,
839848b8605Smrg         sizeof(configs[0]), config_size, _eglFlattenConfig);
840848b8605Smrg
841848b8605Smrg   return EGL_TRUE;
842848b8605Smrg}
843