Fixed missing way of choosing EGL renderable type with QSurfaceFormat.
[profile/ivi/qtbase.git] / src / platformsupport / eglconvenience / qeglconvenience.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QByteArray>
43
44 #include "qeglconvenience_p.h"
45
46 QT_BEGIN_NAMESPACE
47
48 QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format)
49 {
50     int redSize     = format.redBufferSize();
51     int greenSize   = format.greenBufferSize();
52     int blueSize    = format.blueBufferSize();
53     int alphaSize   = format.alphaBufferSize();
54     int depthSize   = format.depthBufferSize();
55     int stencilSize = format.stencilBufferSize();
56     int sampleCount = format.samples();
57
58     // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide
59     // the best performance. The EGL config selection algorithm is a bit stange in this regard:
60     // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard
61     // 32-bit configs completely from the selection. So it then comes to the sorting algorithm.
62     // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort
63     // order is special and described as "by larger _total_ number of color bits.". So EGL will
64     // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on
65     // to say "If the requested number of bits in attrib_list for a particular component is 0,
66     // then the number of bits for that component is not considered". This part of the spec also
67     // seems to imply that setting the red/green/blue bits to zero means none of the components
68     // are considered and EGL disregards the entire sorting rule. It then looks to the next
69     // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being
70     // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are
71     // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit,
72     // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that
73     // if the application sets the red/green/blue size to 5/6/5 on the QSurfaceFormat,
74     // they will probably get a 32-bit config, even when there's an RGB565 config available.
75
76 //    // Now normalize the values so -1 becomes 0
77 //    redSize   = redSize   > 0 ? redSize   : 0;
78 //    greenSize = greenSize > 0 ? greenSize : 0;
79 //    blueSize  = blueSize  > 0 ? blueSize  : 0;
80 //    alphaSize = alphaSize > 0 ? alphaSize : 0;
81 //    depthSize = depthSize > 0 ? depthSize : 0;
82 //    stencilSize = stencilSize > 0 ? stencilSize : 0;
83 //    sampleCount = sampleCount > 0 ? sampleCount : 0;
84
85     QVector<EGLint> configAttributes;
86
87     configAttributes.append(EGL_RED_SIZE);
88     configAttributes.append(redSize > 0 ? redSize : 0);
89
90     configAttributes.append(EGL_GREEN_SIZE);
91     configAttributes.append(greenSize > 0 ? greenSize : 0);
92
93     configAttributes.append(EGL_BLUE_SIZE);
94     configAttributes.append(blueSize > 0 ? blueSize : 0);
95
96     configAttributes.append(EGL_ALPHA_SIZE);
97     configAttributes.append(alphaSize > 0 ? alphaSize : 0);
98
99     configAttributes.append(EGL_DEPTH_SIZE);
100     configAttributes.append(depthSize > 0 ? depthSize : 0);
101
102     configAttributes.append(EGL_STENCIL_SIZE);
103     configAttributes.append(stencilSize > 0 ? stencilSize : 0);
104
105     configAttributes.append(EGL_SAMPLES);
106     configAttributes.append(sampleCount > 0 ? sampleCount : 0);
107
108     configAttributes.append(EGL_SAMPLE_BUFFERS);
109     configAttributes.append(sampleCount > 0);
110
111     return configAttributes;
112 }
113
114 bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes)
115 {
116     int i = -1;
117     // Reduce the complexity of a configuration request to ask for less
118     // because the previous request did not result in success.  Returns
119     // true if the complexity was reduced, or false if no further
120     // reductions in complexity are possible.
121
122     i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
123     if (i >= 0) {
124         configAttributes->remove(i,2);
125     }
126
127 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT
128     // For OpenVG, we sometimes try to create a surface using a pre-multiplied format. If we can't
129     // find a config which supports pre-multiplied formats, remove the flag on the surface type:
130
131     i = configAttributes->indexOf(EGL_SURFACE_TYPE);
132     if (i >= 0) {
133         EGLint surfaceType = configAttributes->at(i +1);
134         if (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) {
135             surfaceType ^= EGL_VG_ALPHA_FORMAT_PRE_BIT;
136             configAttributes->replace(i+1,surfaceType);
137             return true;
138         }
139     }
140 #endif
141
142     // EGL chooses configs with the highest color depth over
143     // those with smaller (but faster) lower color depths. One
144     // way around this is to set EGL_BUFFER_SIZE to 16, which
145     // trumps the others. Of course, there may not be a 16-bit
146     // config available, so it's the first restraint we remove.
147     i = configAttributes->indexOf(EGL_BUFFER_SIZE);
148     if (i >= 0) {
149         if (configAttributes->at(i+1) == 16) {
150             configAttributes->remove(i,2);
151             return true;
152         }
153     }
154
155     i = configAttributes->indexOf(EGL_SAMPLES);
156     if (i >= 0) {
157         EGLint value = configAttributes->value(i+1, 0);
158         if (value > 1)
159             configAttributes->replace(i+1, qMin(EGLint(16), value / 2));
160         else
161             configAttributes->remove(i, 2);
162         return true;
163     }
164
165     i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS);
166     if (i >= 0) {
167         configAttributes->remove(i,2);
168         return true;
169     }
170
171     i = configAttributes->indexOf(EGL_ALPHA_SIZE);
172     if (i >= 0) {
173         configAttributes->remove(i,2);
174 #if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB)
175         i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA);
176         if (i >= 0) {
177             configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB);
178             configAttributes->replace(i+1,TRUE);
179
180         }
181 #endif
182         return true;
183     }
184
185     i = configAttributes->indexOf(EGL_STENCIL_SIZE);
186     if (i >= 0) {
187         if (configAttributes->at(i + 1) > 1)
188             configAttributes->replace(i + 1, 1);
189         else
190             configAttributes->remove(i, 2);
191         return true;
192     }
193
194     i = configAttributes->indexOf(EGL_DEPTH_SIZE);
195     if (i >= 0) {
196         if (configAttributes->at(i + 1) > 1)
197             configAttributes->replace(i + 1, 1);
198         else
199             configAttributes->remove(i, 2);
200         return true;
201     }
202 #ifdef EGL_BIND_TO_TEXTURE_RGB
203     i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB);
204     if (i >= 0) {
205         configAttributes->remove(i,2);
206         return true;
207     }
208 #endif
209
210     return false;
211 }
212
213 EGLConfig q_configFromGLFormat(EGLDisplay display, const QSurfaceFormat &format, bool highestPixelFormat, int surfaceType)
214 {
215     EGLConfig cfg = 0;
216     QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(format);
217     configureAttributes.append(EGL_SURFACE_TYPE);
218     configureAttributes.append(surfaceType);
219
220     configureAttributes.append(EGL_RENDERABLE_TYPE);
221     if (format.renderableType() == QSurfaceFormat::OpenVG)
222         configureAttributes.append(EGL_OPENVG_BIT);
223 #ifdef EGL_VERSION_1_4
224     else if (format.renderableType() == QSurfaceFormat::OpenGL)
225         configureAttributes.append(EGL_OPENGL_BIT);
226 #endif
227     else if (format.majorVersion() == 1)
228         configureAttributes.append(EGL_OPENGL_ES_BIT);
229     else
230         configureAttributes.append(EGL_OPENGL_ES2_BIT);
231
232     configureAttributes.append(EGL_NONE);
233
234     do {
235         // Get the number of matching configurations for this set of properties.
236         EGLint matching = 0;
237         if (!eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching)
238             continue;
239
240         // If we want the best pixel format, then return the first
241         // matching configuration.
242         if (highestPixelFormat) {
243             eglChooseConfig(display, configureAttributes.constData(), &cfg, 1, &matching);
244             if (matching < 1)
245                 continue;
246             return cfg;
247         }
248
249         // Fetch all of the matching configurations and find the
250         // first that matches the pixel format we wanted.
251         int i = configureAttributes.indexOf(EGL_RED_SIZE);
252         int confAttrRed = configureAttributes.at(i+1);
253         i = configureAttributes.indexOf(EGL_GREEN_SIZE);
254         int confAttrGreen = configureAttributes.at(i+1);
255         i = configureAttributes.indexOf(EGL_BLUE_SIZE);
256         int confAttrBlue = configureAttributes.at(i+1);
257         i = configureAttributes.indexOf(EGL_ALPHA_SIZE);
258         int confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1);
259
260         EGLint size = matching;
261         EGLConfig *configs = new EGLConfig [size];
262         eglChooseConfig(display, configureAttributes.constData(), configs, size, &matching);
263         for (EGLint index = 0; index < size; ++index) {
264             EGLint red, green, blue, alpha;
265             eglGetConfigAttrib(display, configs[index], EGL_RED_SIZE, &red);
266             eglGetConfigAttrib(display, configs[index], EGL_GREEN_SIZE, &green);
267             eglGetConfigAttrib(display, configs[index], EGL_BLUE_SIZE, &blue);
268             eglGetConfigAttrib(display, configs[index], EGL_ALPHA_SIZE, &alpha);
269             if ((confAttrRed == 0 || red == confAttrRed) &&
270                 (confAttrGreen == 0 || green == confAttrGreen) &&
271                 (confAttrBlue == 0 || blue == confAttrBlue) &&
272                 (confAttrAlpha == 0 || alpha == confAttrAlpha)) {
273                 cfg = configs[index];
274                 delete [] configs;
275                 return cfg;
276             }
277         }
278         delete [] configs;
279     } while (q_reduceConfigAttributes(&configureAttributes));
280     qWarning("Cant find EGLConfig, returning null config");
281     return 0;
282 }
283
284 QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, const QSurfaceFormat &referenceFormat)
285 {
286     QSurfaceFormat format;
287     EGLint redSize     = 0;
288     EGLint greenSize   = 0;
289     EGLint blueSize    = 0;
290     EGLint alphaSize   = 0;
291     EGLint depthSize   = 0;
292     EGLint stencilSize = 0;
293     EGLint sampleCount = 0;
294     EGLint renderableType = 0;
295
296     eglGetConfigAttrib(display, config, EGL_RED_SIZE,     &redSize);
297     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE,   &greenSize);
298     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,    &blueSize);
299     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE,   &alphaSize);
300     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE,   &depthSize);
301     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize);
302     eglGetConfigAttrib(display, config, EGL_SAMPLES,      &sampleCount);
303     eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType);
304
305     if (referenceFormat.renderableType() == QSurfaceFormat::OpenVG && (renderableType & EGL_OPENVG_BIT))
306         format.setRenderableType(QSurfaceFormat::OpenVG);
307 #ifdef EGL_VERSION_1_4
308     else if (referenceFormat.renderableType() == QSurfaceFormat::OpenGL && (renderableType & EGL_OPENGL_BIT))
309         format.setRenderableType(QSurfaceFormat::OpenGL);
310 #endif
311     else
312         format.setRenderableType(QSurfaceFormat::OpenGLES);
313
314     format.setRedBufferSize(redSize);
315     format.setGreenBufferSize(greenSize);
316     format.setBlueBufferSize(blueSize);
317     format.setAlphaBufferSize(alphaSize);
318     format.setDepthBufferSize(depthSize);
319     format.setStencilBufferSize(stencilSize);
320     format.setSamples(sampleCount);
321     format.setStereo(false);         // EGL doesn't support stereo buffers
322
323     // Clear the EGL error state because some of the above may
324     // have errored out because the attribute is not applicable
325     // to the surface type.  Such errors don't matter.
326     eglGetError();
327
328     return format;
329 }
330
331 bool q_hasEglExtension(EGLDisplay display, const char* extensionName)
332 {
333     QList<QByteArray> extensions =
334         QByteArray(reinterpret_cast<const char *>
335             (eglQueryString(display, EGL_EXTENSIONS))).split(' ');
336     return extensions.contains(extensionName);
337 }
338
339 struct AttrInfo { EGLint attr; const char *name; };
340 static struct AttrInfo attrs[] = {
341     {EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE"},
342     {EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE"},
343     {EGL_BLUE_SIZE, "EGL_BLUE_SIZE"},
344     {EGL_GREEN_SIZE, "EGL_GREEN_SIZE"},
345     {EGL_RED_SIZE, "EGL_RED_SIZE"},
346     {EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE"},
347     {EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE"},
348     {EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT"},
349     {EGL_CONFIG_ID, "EGL_CONFIG_ID"},
350     {EGL_LEVEL, "EGL_LEVEL"},
351     {EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT"},
352     {EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS"},
353     {EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH"},
354     {EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE"},
355     {EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID"},
356     {EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE"},
357     {EGL_SAMPLES, "EGL_SAMPLES"},
358     {EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS"},
359     {EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE"},
360     {EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE"},
361     {EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE"},
362     {EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE"},
363     {EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE"},
364     {EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB"},
365     {EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA"},
366     {EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL"},
367     {EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL"},
368     {-1, 0}};
369
370 void q_printEglConfig(EGLDisplay display, EGLConfig config)
371 {
372     EGLint index;
373     for (index = 0; attrs[index].attr != -1; ++index) {
374         EGLint value;
375         if (eglGetConfigAttrib(display, config, attrs[index].attr, &value)) {
376             qWarning("\t%s: %d\n", attrs[index].name, (int)value);
377         }
378     }
379
380     qWarning("\n");
381 }
382
383 QT_END_NAMESPACE