1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 #include "qeglconvenience_p.h"
48 QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format)
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();
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.
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;
85 QVector<EGLint> configAttributes;
87 configAttributes.append(EGL_RED_SIZE);
88 configAttributes.append(redSize > 0 ? redSize : 0);
90 configAttributes.append(EGL_GREEN_SIZE);
91 configAttributes.append(greenSize > 0 ? greenSize : 0);
93 configAttributes.append(EGL_BLUE_SIZE);
94 configAttributes.append(blueSize > 0 ? blueSize : 0);
96 configAttributes.append(EGL_ALPHA_SIZE);
97 configAttributes.append(alphaSize > 0 ? alphaSize : 0);
99 configAttributes.append(EGL_DEPTH_SIZE);
100 configAttributes.append(depthSize > 0 ? depthSize : 0);
102 configAttributes.append(EGL_STENCIL_SIZE);
103 configAttributes.append(stencilSize > 0 ? stencilSize : 0);
105 configAttributes.append(EGL_SAMPLES);
106 configAttributes.append(sampleCount > 0 ? sampleCount : 0);
108 configAttributes.append(EGL_SAMPLE_BUFFERS);
109 configAttributes.append(sampleCount > 0);
111 return configAttributes;
114 bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes)
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.
122 i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
124 configAttributes->remove(i,2);
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:
131 i = configAttributes->indexOf(EGL_SURFACE_TYPE);
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);
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);
149 if (configAttributes->at(i+1) == 16) {
150 configAttributes->remove(i,2);
155 i = configAttributes->indexOf(EGL_SAMPLES);
157 EGLint value = configAttributes->value(i+1, 0);
159 configAttributes->replace(i+1, qMin(EGLint(16), value / 2));
161 configAttributes->remove(i, 2);
165 i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS);
167 configAttributes->remove(i,2);
171 i = configAttributes->indexOf(EGL_ALPHA_SIZE);
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);
177 configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB);
178 configAttributes->replace(i+1,TRUE);
185 i = configAttributes->indexOf(EGL_STENCIL_SIZE);
187 if (configAttributes->at(i + 1) > 1)
188 configAttributes->replace(i + 1, 1);
190 configAttributes->remove(i, 2);
194 i = configAttributes->indexOf(EGL_DEPTH_SIZE);
196 if (configAttributes->at(i + 1) > 1)
197 configAttributes->replace(i + 1, 1);
199 configAttributes->remove(i, 2);
202 #ifdef EGL_BIND_TO_TEXTURE_RGB
203 i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB);
205 configAttributes->remove(i,2);
213 EGLConfig q_configFromGLFormat(EGLDisplay display, const QSurfaceFormat &format, bool highestPixelFormat, int surfaceType)
216 QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(format);
217 configureAttributes.append(EGL_SURFACE_TYPE);
218 configureAttributes.append(surfaceType);
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);
227 else if (format.majorVersion() == 1)
228 configureAttributes.append(EGL_OPENGL_ES_BIT);
230 configureAttributes.append(EGL_OPENGL_ES2_BIT);
232 configureAttributes.append(EGL_NONE);
235 // Get the number of matching configurations for this set of properties.
237 if (!eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching)
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);
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);
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];
279 } while (q_reduceConfigAttributes(&configureAttributes));
280 qWarning("Cant find EGLConfig, returning null config");
284 QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config, const QSurfaceFormat &referenceFormat)
286 QSurfaceFormat format;
288 EGLint greenSize = 0;
290 EGLint alphaSize = 0;
291 EGLint depthSize = 0;
292 EGLint stencilSize = 0;
293 EGLint sampleCount = 0;
294 EGLint renderableType = 0;
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);
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);
312 format.setRenderableType(QSurfaceFormat::OpenGLES);
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
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.
331 bool q_hasEglExtension(EGLDisplay display, const char* extensionName)
333 QList<QByteArray> extensions =
334 QByteArray(reinterpret_cast<const char *>
335 (eglQueryString(display, EGL_EXTENSIONS))).split(' ');
336 return extensions.contains(extensionName);
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"},
370 void q_printEglConfig(EGLDisplay display, EGLConfig config)
373 for (index = 0; attrs[index].attr != -1; ++index) {
375 if (eglGetConfigAttrib(display, config, attrs[index].attr, &value)) {
376 qWarning("\t%s: %d\n", attrs[index].name, (int)value);