1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QtCore/qdebug.h>
43 #include <QtOpenGL/qgl.h>
44 #include <QtOpenGL/qglpixelbuffer.h>
45 #include "qgl_p.h"
46 #include "qgl_egl_p.h"
47 #include "qglpixelbuffer_p.h"
48 
49 #ifdef Q_WS_X11
50 #include <QtGui/private/qpixmap_x11_p.h>
51 #endif
52 
53 #if defined(Q_OS_SYMBIAN)
54 #include <QtGui/private/qgraphicssystemex_symbian_p.h>
55 #endif
56 
57 QT_BEGIN_NAMESPACE
58 
59 QEglProperties *QGLContextPrivate::extraWindowSurfaceCreationProps = NULL;
60 
qt_eglproperties_set_glformat(QEglProperties & eglProperties,const QGLFormat & glFormat)61 void qt_eglproperties_set_glformat(QEglProperties& eglProperties, const QGLFormat& glFormat)
62 {
63     int redSize     = glFormat.redBufferSize();
64     int greenSize   = glFormat.greenBufferSize();
65     int blueSize    = glFormat.blueBufferSize();
66     int alphaSize   = glFormat.alphaBufferSize();
67     int depthSize   = glFormat.depthBufferSize();
68     int stencilSize = glFormat.stencilBufferSize();
69     int sampleCount = glFormat.samples();
70 
71     bool prefer32Bit = false;
72 #ifdef Q_OS_SYMBIAN
73     // on Symbian we prefer 32-bit configs, unless we're using the low memory GPU
74     prefer32Bit = !QSymbianGraphicsSystemEx::hasBCM2727();
75 #endif
76 
77     if (prefer32Bit) {
78         if (glFormat.alpha() && alphaSize <= 0)
79             alphaSize = 8;
80         if (glFormat.depth() && depthSize <= 0)
81             depthSize = 24;
82         if (glFormat.stencil() && stencilSize <= 0)
83             stencilSize = 8;
84         if (glFormat.sampleBuffers() && sampleCount <= 0)
85             sampleCount = 1;
86 
87         redSize   = redSize   > 0 ? redSize   : 8;
88         greenSize = greenSize > 0 ? greenSize : 8;
89         blueSize  = blueSize  > 0 ? blueSize  : 8;
90         alphaSize = alphaSize > 0 ? alphaSize : 8;
91         depthSize = depthSize > 0 ? depthSize : 24;
92         stencilSize = stencilSize > 0 ? stencilSize : 8;
93         sampleCount = sampleCount >= 0 ? sampleCount : 4;
94     } else {
95         // QGLFormat uses a magic value of -1 to indicate "don't care", even when a buffer of that
96         // type has been requested. So we must check QGLFormat's booleans too if size is -1:
97         if (glFormat.alpha() && alphaSize <= 0)
98             alphaSize = 1;
99         if (glFormat.depth() && depthSize <= 0)
100             depthSize = 1;
101         if (glFormat.stencil() && stencilSize <= 0)
102             stencilSize = 1;
103         if (glFormat.sampleBuffers() && sampleCount <= 0)
104             sampleCount = 1;
105 
106         // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide
107         // the best performance. The EGL config selection algorithm is a bit stange in this regard:
108         // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard
109         // 32-bit configs completely from the selection. So it then comes to the sorting algorithm.
110         // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort
111         // order is special and described as "by larger _total_ number of color bits.". So EGL will
112         // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on
113         // to say "If the requested number of bits in attrib_list for a particular component is 0,
114         // then the number of bits for that component is not considered". This part of the spec also
115         // seems to imply that setting the red/green/blue bits to zero means none of the components
116         // are considered and EGL disregards the entire sorting rule. It then looks to the next
117         // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being
118         // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are
119         // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit,
120         // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that
121         // if the application sets the red/green/blue size to 5/6/5 on the QGLFormat, they will
122         // probably get a 32-bit config, even when there's an RGB565 config available. Oh well.
123 
124         // Now normalize the values so -1 becomes 0
125         redSize   = redSize   > 0 ? redSize   : 0;
126         greenSize = greenSize > 0 ? greenSize : 0;
127         blueSize  = blueSize  > 0 ? blueSize  : 0;
128         alphaSize = alphaSize > 0 ? alphaSize : 0;
129         depthSize = depthSize > 0 ? depthSize : 0;
130         stencilSize = stencilSize > 0 ? stencilSize : 0;
131         sampleCount = sampleCount > 0 ? sampleCount : 0;
132     }
133 
134     eglProperties.setValue(EGL_RED_SIZE,   redSize);
135     eglProperties.setValue(EGL_GREEN_SIZE, greenSize);
136     eglProperties.setValue(EGL_BLUE_SIZE,  blueSize);
137     eglProperties.setValue(EGL_ALPHA_SIZE, alphaSize);
138     eglProperties.setValue(EGL_DEPTH_SIZE, depthSize);
139     eglProperties.setValue(EGL_STENCIL_SIZE, stencilSize);
140     eglProperties.setValue(EGL_SAMPLES, sampleCount);
141     eglProperties.setValue(EGL_SAMPLE_BUFFERS, sampleCount ? 1 : 0);
142 }
143 
144 // Updates "format" with the parameters of the selected configuration.
qt_glformat_from_eglconfig(QGLFormat & format,const EGLConfig config)145 void qt_glformat_from_eglconfig(QGLFormat& format, const EGLConfig config)
146 {
147     EGLint redSize     = 0;
148     EGLint greenSize   = 0;
149     EGLint blueSize    = 0;
150     EGLint alphaSize   = 0;
151     EGLint depthSize   = 0;
152     EGLint stencilSize = 0;
153     EGLint sampleCount = 0;
154     EGLint level       = 0;
155 
156     EGLDisplay display = QEgl::display();
157     eglGetConfigAttrib(display, config, EGL_RED_SIZE,     &redSize);
158     eglGetConfigAttrib(display, config, EGL_GREEN_SIZE,   &greenSize);
159     eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,    &blueSize);
160     eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE,   &alphaSize);
161     eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE,   &depthSize);
162     eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize);
163     eglGetConfigAttrib(display, config, EGL_SAMPLES,      &sampleCount);
164     eglGetConfigAttrib(display, config, EGL_LEVEL,        &level);
165 
166     format.setRedBufferSize(redSize);
167     format.setGreenBufferSize(greenSize);
168     format.setBlueBufferSize(blueSize);
169     format.setAlphaBufferSize(alphaSize);
170     format.setDepthBufferSize(depthSize);
171     format.setStencilBufferSize(stencilSize);
172     format.setSamples(sampleCount);
173     format.setPlane(level);
174     format.setDirectRendering(true); // All EGL contexts are direct-rendered
175     format.setRgba(true);            // EGL doesn't support colour index rendering
176     format.setStereo(false);         // EGL doesn't support stereo buffers
177     format.setAccumBufferSize(0);    // EGL doesn't support accululation buffers
178     format.setDoubleBuffer(true);    // We don't support single buffered EGL contexts
179 
180     // Clear the EGL error state because some of the above may
181     // have errored out because the attribute is not applicable
182     // to the surface type.  Such errors don't matter.
183     eglGetError();
184 }
185 
hasOpenGL()186 bool QGLFormat::hasOpenGL()
187 {
188     return true;
189 }
190 
reset()191 void QGLContext::reset()
192 {
193     Q_D(QGLContext);
194     if (!d->valid)
195         return;
196     d->cleanup();
197     doneCurrent();
198     if (d->eglContext && d->ownsEglContext) {
199         d->destroyEglSurfaceForDevice();
200         delete d->eglContext;
201     }
202     d->ownsEglContext = false;
203     d->eglContext = 0;
204     d->eglSurface = EGL_NO_SURFACE;
205     d->crWin = false;
206     d->sharing = false;
207     d->valid = false;
208     d->transpColor = QColor();
209     d->initDone = false;
210     QGLContextGroup::removeShare(this);
211 }
212 
makeCurrent()213 void QGLContext::makeCurrent()
214 {
215     Q_D(QGLContext);
216     if (!d->valid || !d->eglContext || d->eglSurfaceForDevice() == EGL_NO_SURFACE) {
217         qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
218         return;
219     }
220 
221     if (d->eglContext->makeCurrent(d->eglSurfaceForDevice())) {
222         QGLContextPrivate::setCurrentContext(this);
223         if (!d->workaroundsCached) {
224             d->workaroundsCached = true;
225             const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
226             if (!renderer)
227                 return;
228             if ((strstr(renderer, "SGX") || strstr(renderer, "MBX"))) {
229                 // PowerVR MBX/SGX chips needs to clear all buffers when starting to render
230                 // a new frame, otherwise there will be a performance penalty to pay for
231                 // each frame.
232                 qDebug() << "Found SGX/MBX driver, enabling FullClearOnEveryFrame";
233                 d->workaround_needsFullClearOnEveryFrame = true;
234 
235                 // Older PowerVR SGX drivers (like the one in the N900) have a
236                 // bug which prevents glCopyTexSubImage2D() to work with a POT
237                 // or GL_ALPHA texture bound to an FBO. The only way to
238                 // identify that driver is to check the EGL version number for it.
239                 const char *egl_version = eglQueryString(d->eglContext->display(), EGL_VERSION);
240 
241                 if (egl_version && strstr(egl_version, "1.3")) {
242                     qDebug() << "Found v1.3 driver, enabling brokenFBOReadBack";
243                     d->workaround_brokenFBOReadBack = true;
244                 } else if (egl_version && strstr(egl_version, "1.4")) {
245                     qDebug() << "Found v1.4 driver, enabling brokenTexSubImage";
246                     d->workaround_brokenTexSubImage = true;
247 
248                     // this is a bit complicated; 1.4 version SGX drivers from
249                     // Nokia have fixed the brokenFBOReadBack problem, but
250                     // official drivers from TI haven't, meaning that things
251                     // like the beagleboard are broken unless we hack around it
252                     // - but at the same time, we want to not reduce performance
253                     // by not enabling this elsewhere.
254                     //
255                     // so, let's check for a Nokia-specific addon, and only
256                     // enable if it isn't present.
257                     // (see MeeGo bug #5616)
258                     if (!QEgl::hasExtension("EGL_NOK_image_shared")) {
259                         // no Nokia extension, this is probably a standard SGX
260                         // driver, so enable the workaround
261                         qDebug() << "Found non-Nokia v1.4 driver, enabling brokenFBOReadBack";
262                         d->workaround_brokenFBOReadBack = true;
263                     }
264                 }
265             } else if (strstr(renderer, "VideoCore III")) {
266                 // Some versions of VideoCore III drivers seem to pollute and use
267                 // stencil buffer when using glScissors even if stencil test is disabled.
268                 // Workaround is to clear stencil buffer before disabling scissoring.
269 
270                 // qDebug() << "Found VideoCore III driver, enabling brokenDisableScissorTest";
271                 d->workaround_brokenScissor = true;
272             }
273         }
274     }
275 }
276 
doneCurrent()277 void QGLContext::doneCurrent()
278 {
279     Q_D(QGLContext);
280     if (d->eglContext)
281         d->eglContext->doneCurrent();
282 
283     QGLContextPrivate::setCurrentContext(0);
284 }
285 
286 
swapBuffers() const287 void QGLContext::swapBuffers() const
288 {
289     Q_D(const QGLContext);
290     if (!d->valid || !d->eglContext)
291         return;
292 
293     d->eglContext->swapBuffers(d->eglSurfaceForDevice());
294 }
295 
destroyEglSurfaceForDevice()296 void QGLContextPrivate::destroyEglSurfaceForDevice()
297 {
298     if (eglSurface != EGL_NO_SURFACE) {
299 #if defined(Q_WS_X11) || defined(Q_OS_SYMBIAN)
300         // Make sure we don't call eglDestroySurface on a surface which
301         // was created for a different winId. This applies only to QGLWidget
302         // paint device, so make sure this is the one we're operating on
303         // (as opposed to a QGLWindowSurface use case).
304         if (paintDevice && paintDevice->devType() == QInternal::Widget) {
305             QWidget *w = static_cast<QWidget *>(paintDevice);
306             if (QGLWidget *wgl = qobject_cast<QGLWidget *>(w)) {
307                 if (wgl->d_func()->eglSurfaceWindowId != wgl->winId()) {
308                     qWarning("WARNING: Potential EGL surface leak! Not destroying surface.");
309                     eglSurface = EGL_NO_SURFACE;
310                     return;
311                 }
312             }
313         }
314 #endif
315         eglDestroySurface(eglContext->display(), eglSurface);
316         eglSurface = EGL_NO_SURFACE;
317     }
318 }
319 
eglSurfaceForDevice() const320 EGLSurface QGLContextPrivate::eglSurfaceForDevice() const
321 {
322     // If a QPixmapData had to create the QGLContext, we don't have a paintDevice
323     if (!paintDevice)
324         return eglSurface;
325 
326 #ifdef Q_WS_X11
327     if (paintDevice->devType() == QInternal::Pixmap) {
328         QPixmapData *pmd = static_cast<QPixmap*>(paintDevice)->data_ptr().data();
329         if (pmd->classId() == QPixmapData::X11Class) {
330             QX11PixmapData* x11PixmapData = static_cast<QX11PixmapData*>(pmd);
331             return (EGLSurface)x11PixmapData->gl_surface;
332         }
333     }
334 #endif
335 
336     if (paintDevice->devType() == QInternal::Pbuffer) {
337         QGLPixelBuffer* pbuf = static_cast<QGLPixelBuffer*>(paintDevice);
338         return pbuf->d_func()->pbuf;
339     }
340 
341     return eglSurface;
342 }
343 
swapRegion(const QRegion & region)344 void QGLContextPrivate::swapRegion(const QRegion &region)
345 {
346     if (!valid || !eglContext)
347         return;
348 
349     eglContext->swapBuffersRegion2NOK(eglSurfaceForDevice(), &region);
350 }
351 
setExtraWindowSurfaceCreationProps(QEglProperties * props)352 void QGLContextPrivate::setExtraWindowSurfaceCreationProps(QEglProperties *props)
353 {
354     extraWindowSurfaceCreationProps = props;
355 }
356 
setMouseTracking(bool enable)357 void QGLWidget::setMouseTracking(bool enable)
358 {
359     QWidget::setMouseTracking(enable);
360 }
361 
overlayTransparentColor() const362 QColor QGLContext::overlayTransparentColor() const
363 {
364     return d_func()->transpColor;
365 }
366 
colorIndex(const QColor & c) const367 uint QGLContext::colorIndex(const QColor &c) const
368 {
369     Q_UNUSED(c);
370     return 0;
371 }
372 
generateFontDisplayLists(const QFont & fnt,int listBase)373 void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
374 {
375     Q_UNUSED(fnt);
376     Q_UNUSED(listBase);
377 }
378 
getProcAddress(const QString & proc) const379 void *QGLContext::getProcAddress(const QString &proc) const
380 {
381     return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
382 }
383 
renderCxPm(QPixmap *)384 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
385 {
386     return false;
387 }
388 
389 QT_END_NAMESPACE
390