1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qapplication.h"
41 #include "qplatformdefs.h"
42 #include "qgl.h"
43 #include <qdebug.h>
44 #include <qglfunctions.h>
45 
46 #include <qdatetime.h>
47 
48 #include <stdlib.h> // malloc
49 
50 #include "qpixmap.h"
51 #include "qimage.h"
52 #include "qgl_p.h"
53 
54 #include "gl2paintengineex/qpaintengineex_opengl2_p.h"
55 
56 #include <qpa/qplatformopenglcontext.h>
57 
58 #include <qglpixelbuffer.h>
59 #include <qglframebufferobject.h>
60 #include <private/qopenglextensions_p.h>
61 
62 #include <private/qimage_p.h>
63 #include <qpa/qplatformpixmap.h>
64 #include <private/qglpixelbuffer_p.h>
65 #include <private/qimagepixmapcleanuphooks_p.h>
66 #include "qcolormap.h"
67 #include "qfile.h"
68 #include <qmutex.h>
69 
70 #include "qsurfaceformat.h"
71 #include <private/qapplication_p.h>
72 #include <qpa/qplatformopenglcontext.h>
73 #include <qpa/qplatformwindow.h>
74 
75 #ifndef QT_OPENGL_ES_2
76 #include <qopenglfunctions_1_1.h>
77 #endif
78 
79 // #define QT_GL_CONTEXT_RESOURCE_DEBUG
80 
81 QT_BEGIN_NAMESPACE
82 
83 class QGLDefaultExtensions
84 {
85 public:
QGLDefaultExtensions()86     QGLDefaultExtensions()
87     {
88         QGLTemporaryContext tempContext;
89         Q_ASSERT(QOpenGLContext::currentContext());
90         QOpenGLExtensions *ext = qgl_extensions();
91         Q_ASSERT(ext);
92         extensions = ext->openGLExtensions();
93         features = ext->openGLFeatures();
94     }
95 
96     QOpenGLFunctions::OpenGLFeatures features;
97     QOpenGLExtensions::OpenGLExtensions extensions;
98 };
99 
Q_GLOBAL_STATIC(QGLDefaultExtensions,qtDefaultExtensions)100 Q_GLOBAL_STATIC(QGLDefaultExtensions, qtDefaultExtensions)
101 
102 bool qgl_hasFeature(QOpenGLFunctions::OpenGLFeature feature)
103 {
104     if (QOpenGLContext::currentContext())
105         return QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(feature);
106     return qtDefaultExtensions()->features & feature;
107 }
108 
qgl_hasExtension(QOpenGLExtensions::OpenGLExtension extension)109 bool qgl_hasExtension(QOpenGLExtensions::OpenGLExtension extension)
110 {
111     if (QOpenGLContext::currentContext())
112         return qgl_extensions()->hasOpenGLExtension(extension);
113     return qtDefaultExtensions()->extensions & extension;
114 }
115 
116 QOpenGLExtensions::OpenGLExtensions extensions;
117 
118 /*
119     Returns the GL extensions for the current QOpenGLContext. If there is no
120     current QOpenGLContext, a default context will be created and the extensions
121     for that context will be returned instead.
122 */
qgl_extensions()123 QOpenGLExtensions* qgl_extensions()
124 {
125     if (QOpenGLContext *context = QOpenGLContext::currentContext())
126         return static_cast<QOpenGLExtensions *>(context->functions());
127 
128     Q_ASSERT(false);
129     return 0;
130 }
131 
qgl_functions()132 QOpenGLFunctions *qgl_functions()
133 {
134     return qgl_extensions(); // QOpenGLExtensions is just a subclass of QOpenGLFunctions
135 }
136 
137 #ifndef QT_OPENGL_ES_2
qgl1_functions()138 QOpenGLFunctions_1_1 *qgl1_functions()
139 {
140     QOpenGLFunctions_1_1 *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_1_1>();
141     f->initializeOpenGLFunctions();
142     return f;
143 }
144 #endif
145 
146 struct QGLThreadContext {
~QGLThreadContextQGLThreadContext147     ~QGLThreadContext() {
148         if (context)
149             context->doneCurrent();
150     }
151     QGLContext *context;
152 };
153 
154 Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
155 
156 class QGLDefaultOverlayFormat: public QGLFormat
157 {
158 public:
QGLDefaultOverlayFormat()159     inline QGLDefaultOverlayFormat()
160     {
161         setOption(QGL::FormatOption(0xffffU << 16)); // turn off all options
162         setOption(QGL::DirectRendering);
163         setPlane(1);
164     }
165 };
Q_GLOBAL_STATIC(QGLDefaultOverlayFormat,defaultOverlayFormatInstance)166 Q_GLOBAL_STATIC(QGLDefaultOverlayFormat, defaultOverlayFormatInstance)
167 
168 Q_GLOBAL_STATIC(QGLSignalProxy, theSignalProxy)
169 QGLSignalProxy *QGLSignalProxy::instance()
170 {
171     QGLSignalProxy *proxy = theSignalProxy();
172     if (proxy && qApp && proxy->thread() != qApp->thread()) {
173         if (proxy->thread() == QThread::currentThread())
174             proxy->moveToThread(qApp->thread());
175     }
176     return proxy;
177 }
178 
179 
180 /*!
181     \namespace QGL
182     \inmodule QtOpenGL
183 
184     \brief The QGL namespace specifies miscellaneous identifiers used
185     in the Qt OpenGL module.
186 */
187 
188 /*!
189     \enum QGL::FormatOption
190 
191     This enum specifies the format options that can be used to configure an OpenGL
192     context. These are set using QGLFormat::setOption().
193 
194     \value DoubleBuffer      Specifies the use of double buffering.
195     \value DepthBuffer       Enables the use of a depth buffer.
196     \value Rgba              Specifies that the context should use RGBA as its pixel format.
197     \value AlphaChannel      Enables the use of an alpha channel.
198     \value AccumBuffer       Enables the use of an accumulation buffer.
199     \value StencilBuffer     Enables the use of a stencil buffer.
200     \value StereoBuffers     Enables the use of a stereo buffers for use with visualization hardware.
201     \value DirectRendering   Specifies that the context is used for direct rendering to a display.
202     \value HasOverlay        Enables the use of an overlay.
203     \value SampleBuffers     Enables the use of sample buffers.
204     \value DeprecatedFunctions      Enables the use of deprecated functionality for OpenGL 3.x
205                                     contexts. A context with deprecated functionality enabled is
206                                     called a full context in the OpenGL specification.
207     \value SingleBuffer      Specifies the use of a single buffer, as opposed to double buffers.
208     \value NoDepthBuffer     Disables the use of a depth buffer.
209     \value ColorIndex        Specifies that the context should use a color index as its pixel format.
210     \value NoAlphaChannel    Disables the use of an alpha channel.
211     \value NoAccumBuffer     Disables the use of an accumulation buffer.
212     \value NoStencilBuffer   Disables the use of a stencil buffer.
213     \value NoStereoBuffers   Disables the use of stereo buffers.
214     \value IndirectRendering Specifies that the context is used for indirect rendering to a buffer.
215     \value NoOverlay         Disables the use of an overlay.
216     \value NoSampleBuffers   Disables the use of sample buffers.
217     \value NoDeprecatedFunctions    Disables the use of deprecated functionality for OpenGL 3.x
218                                     contexts. A context with deprecated functionality disabled is
219                                     called a forward compatible context in the OpenGL specification.
220 */
221 
222 /*****************************************************************************
223   QGLFormat implementation
224  *****************************************************************************/
225 
226 
227 /*!
228     \class QGLFormat
229     \inmodule QtOpenGL
230     \obsolete
231 
232     \brief The QGLFormat class specifies the display format of an OpenGL
233     rendering context.
234 
235     A display format has several characteristics:
236     \list
237     \li \l{setDoubleBuffer()}{Double or single buffering.}
238     \li \l{setDepth()}{Depth buffer.}
239     \li \l{setRgba()}{RGBA or color index mode.}
240     \li \l{setAlpha()}{Alpha channel.}
241     \li \l{setAccum()}{Accumulation buffer.}
242     \li \l{setStencil()}{Stencil buffer.}
243     \li \l{setStereo()}{Stereo buffers.}
244     \li \l{setDirectRendering()}{Direct rendering.}
245     \li \l{setOverlay()}{Presence of an overlay.}
246     \li \l{setPlane()}{Plane of an overlay.}
247     \li \l{setSampleBuffers()}{Multisample buffers.}
248     \endlist
249 
250     You can also specify preferred bit depths for the color buffer,
251     depth buffer, alpha buffer, accumulation buffer and the stencil
252     buffer with the functions: setRedBufferSize(), setGreenBufferSize(),
253     setBlueBufferSize(), setDepthBufferSize(), setAlphaBufferSize(),
254     setAccumBufferSize() and setStencilBufferSize().
255 
256     Note that even if you specify that you prefer a 32 bit depth
257     buffer (e.g. with setDepthBufferSize(32)), the format that is
258     chosen may not have a 32 bit depth buffer, even if there is a
259     format available with a 32 bit depth buffer. The main reason for
260     this is how the system dependant picking algorithms work on the
261     different platforms, and some format options may have higher
262     precedence than others.
263 
264     You create and tell a QGLFormat object what rendering options you
265     want from an OpenGL rendering context.
266 
267     OpenGL drivers or accelerated hardware may or may not support
268     advanced features such as alpha channel or stereographic viewing.
269     If you request some features that the driver/hardware does not
270     provide when you create a QGLWidget, you will get a rendering
271     context with the nearest subset of features.
272 
273     There are different ways to define the display characteristics of
274     a rendering context. One is to create a QGLFormat and make it the
275     default for the entire application:
276     \snippet code/src_opengl_qgl.cpp 0
277 
278     Or you can specify the desired format when creating an object of
279     your QGLWidget subclass:
280     \snippet code/src_opengl_qgl.cpp 1
281 
282     After the widget has been created, you can find out which of the
283     requested features the system was able to provide:
284     \snippet code/src_opengl_qgl.cpp 2
285 
286     \legalese
287         OpenGL is a trademark of Silicon Graphics, Inc. in the
288         United States and other countries.
289     \endlegalese
290 
291     \sa QGLContext, QGLWidget
292 */
293 
294 #ifndef QT_OPENGL_ES
295 
transform_point(GLdouble out[4],const GLdouble m[16],const GLdouble in[4])296 static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
297 {
298 #define M(row,col)  m[col*4+row]
299     out[0] =
300         M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
301     out[1] =
302         M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
303     out[2] =
304         M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
305     out[3] =
306         M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
307 #undef M
308 }
309 
qgluProject(GLdouble objx,GLdouble objy,GLdouble objz,const GLdouble model[16],const GLdouble proj[16],const GLint viewport[4],GLdouble * winx,GLdouble * winy,GLdouble * winz)310 static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
311            const GLdouble model[16], const GLdouble proj[16],
312            const GLint viewport[4],
313            GLdouble * winx, GLdouble * winy, GLdouble * winz)
314 {
315    GLdouble in[4], out[4];
316 
317    in[0] = objx;
318    in[1] = objy;
319    in[2] = objz;
320    in[3] = 1.0;
321    transform_point(out, model, in);
322    transform_point(in, proj, out);
323 
324    if (in[3] == 0.0)
325       return GL_FALSE;
326 
327    in[0] /= in[3];
328    in[1] /= in[3];
329    in[2] /= in[3];
330 
331    *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
332    *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
333 
334    *winz = (1 + in[2]) / 2;
335    return GL_TRUE;
336 }
337 
338 #endif // !QT_OPENGL_ES
339 
340 /*!
341     Constructs a QGLFormat object with the following default settings:
342     \list
343     \li \l{setDoubleBuffer()}{Double buffer:} Enabled.
344     \li \l{setDepth()}{Depth buffer:} Enabled.
345     \li \l{setRgba()}{RGBA:} Enabled (i.e., color index disabled).
346     \li \l{setAlpha()}{Alpha channel:} Disabled.
347     \li \l{setAccum()}{Accumulator buffer:} Disabled.
348     \li \l{setStencil()}{Stencil buffer:} Enabled.
349     \li \l{setStereo()}{Stereo:} Disabled.
350     \li \l{setDirectRendering()}{Direct rendering:} Enabled.
351     \li \l{setOverlay()}{Overlay:} Disabled.
352     \li \l{setPlane()}{Plane:} 0 (i.e., normal plane).
353     \li \l{setSampleBuffers()}{Multisample buffers:} Disabled.
354     \endlist
355 */
356 
QGLFormat()357 QGLFormat::QGLFormat()
358 {
359     d = new QGLFormatPrivate;
360 }
361 
362 
363 /*!
364     Creates a QGLFormat object that is a copy of the current
365     defaultFormat().
366 
367     If \a options is not 0, the default format is modified by the
368     specified format options. The \a options parameter should be
369     QGL::FormatOption values OR'ed together.
370 
371     This constructor makes it easy to specify a certain desired format
372     in classes derived from QGLWidget, for example:
373     \snippet code/src_opengl_qgl.cpp 3
374 
375     Note that there are QGL::FormatOption values to turn format settings
376     both on and off, e.g. QGL::DepthBuffer and QGL::NoDepthBuffer,
377     QGL::DirectRendering and QGL::IndirectRendering, etc.
378 
379     The \a plane parameter defaults to 0 and is the plane which this
380     format should be associated with. Not all OpenGL implementations
381     supports overlay/underlay rendering planes.
382 
383     \sa defaultFormat(), setOption(), setPlane()
384 */
385 
QGLFormat(QGL::FormatOptions options,int plane)386 QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
387 {
388     d = new QGLFormatPrivate;
389     QGL::FormatOptions newOpts = options;
390     d->opts = defaultFormat().d->opts;
391     d->opts |= (newOpts & 0xffff);
392     d->opts &= ~(newOpts >> 16);
393     d->pln = plane;
394 }
395 
396 /*!
397     \internal
398 */
detach()399 void QGLFormat::detach()
400 {
401     if (d->ref.loadRelaxed() != 1) {
402         QGLFormatPrivate *newd = new QGLFormatPrivate(d);
403         if (!d->ref.deref())
404             delete d;
405         d = newd;
406     }
407 }
408 
409 /*!
410     Constructs a copy of \a other.
411 */
412 
QGLFormat(const QGLFormat & other)413 QGLFormat::QGLFormat(const QGLFormat &other)
414 {
415     d = other.d;
416     d->ref.ref();
417 }
418 
419 /*!
420     Assigns \a other to this object.
421 */
422 
operator =(const QGLFormat & other)423 QGLFormat &QGLFormat::operator=(const QGLFormat &other)
424 {
425     if (d != other.d) {
426         other.d->ref.ref();
427         if (!d->ref.deref())
428             delete d;
429         d = other.d;
430     }
431     return *this;
432 }
433 
434 /*!
435     Destroys the QGLFormat.
436 */
~QGLFormat()437 QGLFormat::~QGLFormat()
438 {
439     if (!d->ref.deref())
440         delete d;
441 }
442 
443 /*!
444     Returns an OpenGL format for the window format specified by \a format.
445 */
fromSurfaceFormat(const QSurfaceFormat & format)446 QGLFormat QGLFormat::fromSurfaceFormat(const QSurfaceFormat &format)
447 {
448     QGLFormat retFormat;
449     if (format.alphaBufferSize() >= 0)
450         retFormat.setAlphaBufferSize(format.alphaBufferSize());
451     if (format.blueBufferSize() >= 0)
452         retFormat.setBlueBufferSize(format.blueBufferSize());
453     if (format.greenBufferSize() >= 0)
454         retFormat.setGreenBufferSize(format.greenBufferSize());
455     if (format.redBufferSize() >= 0)
456         retFormat.setRedBufferSize(format.redBufferSize());
457     if (format.depthBufferSize() >= 0)
458         retFormat.setDepthBufferSize(format.depthBufferSize());
459     if (format.samples() > 1) {
460         retFormat.setSampleBuffers(true);
461         retFormat.setSamples(format.samples());
462     }
463     if (format.stencilBufferSize() > 0) {
464         retFormat.setStencil(true);
465         retFormat.setStencilBufferSize(format.stencilBufferSize());
466     }
467     retFormat.setSwapInterval(format.swapInterval());
468     retFormat.setDoubleBuffer(format.swapBehavior() != QSurfaceFormat::SingleBuffer);
469     retFormat.setStereo(format.stereo());
470     retFormat.setVersion(format.majorVersion(), format.minorVersion());
471     retFormat.setProfile(static_cast<QGLFormat::OpenGLContextProfile>(format.profile()));
472     return retFormat;
473 }
474 
475 /*!
476     Returns a window format for the OpenGL format specified by \a format.
477 */
toSurfaceFormat(const QGLFormat & format)478 QSurfaceFormat QGLFormat::toSurfaceFormat(const QGLFormat &format)
479 {
480     QSurfaceFormat retFormat;
481     if (format.alpha())
482         retFormat.setAlphaBufferSize(format.alphaBufferSize() == -1 ? 1 : format.alphaBufferSize());
483     if (format.blueBufferSize() >= 0)
484         retFormat.setBlueBufferSize(format.blueBufferSize());
485     if (format.greenBufferSize() >= 0)
486         retFormat.setGreenBufferSize(format.greenBufferSize());
487     if (format.redBufferSize() >= 0)
488         retFormat.setRedBufferSize(format.redBufferSize());
489     if (format.depth())
490         retFormat.setDepthBufferSize(format.depthBufferSize() == -1 ? 1 : format.depthBufferSize());
491     retFormat.setSwapBehavior(format.doubleBuffer() ? QSurfaceFormat::DoubleBuffer : QSurfaceFormat::SingleBuffer);
492     if (format.sampleBuffers())
493         retFormat.setSamples(format.samples() == -1 ? 4 : format.samples());
494     if (format.stencil())
495         retFormat.setStencilBufferSize(format.stencilBufferSize() == -1 ? 1 : format.stencilBufferSize());
496     retFormat.setSwapInterval(format.swapInterval());
497     retFormat.setStereo(format.stereo());
498     retFormat.setMajorVersion(format.majorVersion());
499     retFormat.setMinorVersion(format.minorVersion());
500     retFormat.setProfile(static_cast<QSurfaceFormat::OpenGLContextProfile>(format.profile()));
501     // QGLFormat has no way to set DeprecatedFunctions, that is, to tell that forward
502     // compatibility should not be requested. Some drivers fail to ignore the fwdcompat
503     // bit with compatibility profiles so make sure it is not set.
504     if (format.profile() == QGLFormat::CompatibilityProfile)
505         retFormat.setOption(QSurfaceFormat::DeprecatedFunctions);
506     return retFormat;
507 }
508 
setupSharing()509 void QGLContextPrivate::setupSharing() {
510     Q_Q(QGLContext);
511     QOpenGLContext *sharedContext = guiGlContext->shareContext();
512     if (sharedContext) {
513         QGLContext *actualSharedContext = QGLContext::fromOpenGLContext(sharedContext);
514         sharing = true;
515         QGLContextGroup::addShare(q, actualSharedContext);
516     }
517 }
518 
refreshCurrentFbo()519 void QGLContextPrivate::refreshCurrentFbo()
520 {
521     QOpenGLContextPrivate *guiGlContextPrivate =
522         guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0;
523 
524     // if QOpenGLFramebufferObjects have been used in the mean-time, we've lost our cached value
525     if (guiGlContextPrivate && guiGlContextPrivate->qgl_current_fbo_invalid) {
526         GLint current;
527         QOpenGLFunctions *funcs = qgl_functions();
528         funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &current);
529 
530         current_fbo = current;
531 
532         guiGlContextPrivate->qgl_current_fbo_invalid = false;
533     }
534 }
535 
setCurrentFbo(GLuint fbo)536 void QGLContextPrivate::setCurrentFbo(GLuint fbo)
537 {
538     current_fbo = fbo;
539 
540     QOpenGLContextPrivate *guiGlContextPrivate =
541         guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0;
542 
543     if (guiGlContextPrivate)
544         guiGlContextPrivate->qgl_current_fbo_invalid = false;
545 }
546 
547 
548 /*!
549     \fn bool QGLFormat::doubleBuffer() const
550 
551     Returns \c true if double buffering is enabled; otherwise returns
552     false. Double buffering is enabled by default.
553 
554     \sa setDoubleBuffer()
555 */
556 
557 /*!
558     If \a enable is true sets double buffering; otherwise sets single
559     buffering.
560 
561     Double buffering is enabled by default.
562 
563     Double buffering is a technique where graphics are rendered on an
564     off-screen buffer and not directly to the screen. When the drawing
565     has been completed, the program calls a swapBuffers() function to
566     exchange the screen contents with the buffer. The result is
567     flicker-free drawing and often better performance.
568 
569     Note that single buffered contexts are currently not supported
570     with EGL.
571 
572     \sa doubleBuffer(), QGLContext::swapBuffers(),
573     QGLWidget::swapBuffers()
574 */
575 
setDoubleBuffer(bool enable)576 void QGLFormat::setDoubleBuffer(bool enable)
577 {
578     setOption(enable ? QGL::DoubleBuffer : QGL::SingleBuffer);
579 }
580 
581 
582 /*!
583     \fn bool QGLFormat::depth() const
584 
585     Returns \c true if the depth buffer is enabled; otherwise returns
586     false. The depth buffer is enabled by default.
587 
588     \sa setDepth(), setDepthBufferSize()
589 */
590 
591 /*!
592     If \a enable is true enables the depth buffer; otherwise disables
593     the depth buffer.
594 
595     The depth buffer is enabled by default.
596 
597     The purpose of a depth buffer (or Z-buffering) is to remove hidden
598     surfaces. Pixels are assigned Z values based on the distance to
599     the viewer. A pixel with a high Z value is closer to the viewer
600     than a pixel with a low Z value. This information is used to
601     decide whether to draw a pixel or not.
602 
603     \sa depth(), setDepthBufferSize()
604 */
605 
setDepth(bool enable)606 void QGLFormat::setDepth(bool enable)
607 {
608     setOption(enable ? QGL::DepthBuffer : QGL::NoDepthBuffer);
609 }
610 
611 
612 /*!
613     \fn bool QGLFormat::rgba() const
614 
615     Returns \c true if RGBA color mode is set. Returns \c false if color
616     index mode is set. The default color mode is RGBA.
617 
618     \sa setRgba()
619 */
620 
621 /*!
622     If \a enable is true sets RGBA mode. If \a enable is false sets
623     color index mode.
624 
625     The default color mode is RGBA.
626 
627     RGBA is the preferred mode for most OpenGL applications. In RGBA
628     color mode you specify colors as red + green + blue + alpha
629     quadruplets.
630 
631     In color index mode you specify an index into a color lookup
632     table.
633 
634     \sa rgba()
635 */
636 
setRgba(bool enable)637 void QGLFormat::setRgba(bool enable)
638 {
639     setOption(enable ? QGL::Rgba : QGL::ColorIndex);
640 }
641 
642 
643 /*!
644     \fn bool QGLFormat::alpha() const
645 
646     Returns \c true if the alpha buffer in the framebuffer is enabled;
647     otherwise returns \c false. The alpha buffer is disabled by default.
648 
649     \sa setAlpha(), setAlphaBufferSize()
650 */
651 
652 /*!
653     If \a enable is true enables the alpha buffer; otherwise disables
654     the alpha buffer.
655 
656     The alpha buffer is disabled by default.
657 
658     The alpha buffer is typically used for implementing transparency
659     or translucency. The A in RGBA specifies the transparency of a
660     pixel.
661 
662     \sa alpha(), setAlphaBufferSize()
663 */
664 
setAlpha(bool enable)665 void QGLFormat::setAlpha(bool enable)
666 {
667     setOption(enable ? QGL::AlphaChannel : QGL::NoAlphaChannel);
668 }
669 
670 
671 /*!
672     \fn bool QGLFormat::accum() const
673 
674     Returns \c true if the accumulation buffer is enabled; otherwise
675     returns \c false. The accumulation buffer is disabled by default.
676 
677     \sa setAccum(), setAccumBufferSize()
678 */
679 
680 /*!
681     If \a enable is true enables the accumulation buffer; otherwise
682     disables the accumulation buffer.
683 
684     The accumulation buffer is disabled by default.
685 
686     The accumulation buffer is used to create blur effects and
687     multiple exposures.
688 
689     \sa accum(), setAccumBufferSize()
690 */
691 
setAccum(bool enable)692 void QGLFormat::setAccum(bool enable)
693 {
694     setOption(enable ? QGL::AccumBuffer : QGL::NoAccumBuffer);
695 }
696 
697 
698 /*!
699     \fn bool QGLFormat::stencil() const
700 
701     Returns \c true if the stencil buffer is enabled; otherwise returns
702     false. The stencil buffer is enabled by default.
703 
704     \sa setStencil(), setStencilBufferSize()
705 */
706 
707 /*!
708     If \a enable is true enables the stencil buffer; otherwise
709     disables the stencil buffer.
710 
711     The stencil buffer is enabled by default.
712 
713     The stencil buffer masks certain parts of the drawing area so that
714     masked parts are not drawn on.
715 
716     \sa stencil(), setStencilBufferSize()
717 */
718 
setStencil(bool enable)719 void QGLFormat::setStencil(bool enable)
720 {
721     setOption(enable ? QGL::StencilBuffer: QGL::NoStencilBuffer);
722 }
723 
724 
725 /*!
726     \fn bool QGLFormat::stereo() const
727 
728     Returns \c true if stereo buffering is enabled; otherwise returns
729     false. Stereo buffering is disabled by default.
730 
731     \sa setStereo()
732 */
733 
734 /*!
735     If \a enable is true enables stereo buffering; otherwise disables
736     stereo buffering.
737 
738     Stereo buffering is disabled by default.
739 
740     Stereo buffering provides extra color buffers to generate left-eye
741     and right-eye images.
742 
743     \sa stereo()
744 */
745 
setStereo(bool enable)746 void QGLFormat::setStereo(bool enable)
747 {
748     setOption(enable ? QGL::StereoBuffers : QGL::NoStereoBuffers);
749 }
750 
751 
752 /*!
753     \fn bool QGLFormat::directRendering() const
754 
755     Returns \c true if direct rendering is enabled; otherwise returns
756     false.
757 
758     Direct rendering is enabled by default.
759 
760     \sa setDirectRendering()
761 */
762 
763 /*!
764     If \a enable is true enables direct rendering; otherwise disables
765     direct rendering.
766 
767     Direct rendering is enabled by default.
768 
769     Enabling this option will make OpenGL bypass the underlying window
770     system and render directly from hardware to the screen, if this is
771     supported by the system.
772 
773     \sa directRendering()
774 */
775 
setDirectRendering(bool enable)776 void QGLFormat::setDirectRendering(bool enable)
777 {
778     setOption(enable ? QGL::DirectRendering : QGL::IndirectRendering);
779 }
780 
781 /*!
782     \fn bool QGLFormat::sampleBuffers() const
783 
784     Returns \c true if multisample buffer support is enabled; otherwise
785     returns \c false.
786 
787     The multisample buffer is disabled by default.
788 
789     \sa setSampleBuffers()
790 */
791 
792 /*!
793     If \a enable is true, a GL context with multisample buffer support
794     is picked; otherwise ignored.
795 
796     \sa sampleBuffers(), setSamples(), samples()
797 */
setSampleBuffers(bool enable)798 void QGLFormat::setSampleBuffers(bool enable)
799 {
800     setOption(enable ? QGL::SampleBuffers : QGL::NoSampleBuffers);
801 }
802 
803 /*!
804     Returns the number of samples per pixel when multisampling is
805     enabled. By default, the highest number of samples that is
806     available is used.
807 
808     \sa setSampleBuffers(), sampleBuffers(), setSamples()
809 */
samples() const810 int QGLFormat::samples() const
811 {
812    return d->numSamples;
813 }
814 
815 /*!
816     Set the preferred number of samples per pixel when multisampling
817     is enabled to \a numSamples. By default, the highest number of
818     samples available is used.
819 
820     \sa setSampleBuffers(), sampleBuffers(), samples()
821 */
setSamples(int numSamples)822 void QGLFormat::setSamples(int numSamples)
823 {
824     detach();
825     if (numSamples < 0) {
826         qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
827         return;
828     }
829     d->numSamples = numSamples;
830     setSampleBuffers(numSamples > 0);
831 }
832 
833 /*!
834     \since 4.2
835 
836     Set the preferred swap interval. This can be used to sync the GL
837     drawing into a system window to the vertical refresh of the screen.
838     Setting an \a interval value of 0 will turn the vertical refresh syncing
839     off, any value higher than 0 will turn the vertical syncing on.
840 
841     Under Windows and under X11, where the \c{WGL_EXT_swap_control}
842     and \c{GLX_SGI_video_sync} extensions are used, the \a interval
843     parameter can be used to set the minimum number of video frames
844     that are displayed before a buffer swap will occur. In effect,
845     setting the \a interval to 10, means there will be 10 vertical
846     retraces between every buffer swap.
847 
848     Under Windows the \c{WGL_EXT_swap_control} extension has to be present,
849     and under X11 the \c{GLX_SGI_video_sync} extension has to be present.
850 */
setSwapInterval(int interval)851 void QGLFormat::setSwapInterval(int interval)
852 {
853     detach();
854     d->swapInterval = interval;
855 }
856 
857 /*!
858     \since 4.2
859 
860     Returns the currently set swap interval. -1 is returned if setting
861     the swap interval isn't supported in the system GL implementation.
862 */
swapInterval() const863 int QGLFormat::swapInterval() const
864 {
865     return d->swapInterval;
866 }
867 
868 /*!
869     \fn bool QGLFormat::hasOverlay() const
870 
871     Returns \c true if overlay plane is enabled; otherwise returns \c false.
872 
873     Overlay is disabled by default.
874 
875     \sa setOverlay()
876 */
877 
878 /*!
879     If \a enable is true enables an overlay plane; otherwise disables
880     the overlay plane.
881 
882     Enabling the overlay plane will cause QGLWidget to create an
883     additional context in an overlay plane. See the QGLWidget
884     documentation for further information.
885 
886     \sa hasOverlay()
887 */
888 
setOverlay(bool enable)889 void QGLFormat::setOverlay(bool enable)
890 {
891     setOption(enable ? QGL::HasOverlay : QGL::NoOverlay);
892 }
893 
894 /*!
895     Returns the plane of this format. The default for normal formats
896     is 0, which means the normal plane. The default for overlay
897     formats is 1, which is the first overlay plane.
898 
899     \sa setPlane(), defaultOverlayFormat()
900 */
plane() const901 int QGLFormat::plane() const
902 {
903     return d->pln;
904 }
905 
906 /*!
907     Sets the requested plane to \a plane. 0 is the normal plane, 1 is
908     the first overlay plane, 2 is the second overlay plane, etc.; -1,
909     -2, etc. are underlay planes.
910 
911     Note that in contrast to other format specifications, the plane
912     specifications will be matched exactly. This means that if you
913     specify a plane that the underlying OpenGL system cannot provide,
914     an \l{QGLWidget::isValid()}{invalid} QGLWidget will be
915     created.
916 
917     \sa plane()
918 */
setPlane(int plane)919 void QGLFormat::setPlane(int plane)
920 {
921     detach();
922     d->pln = plane;
923 }
924 
925 /*!
926     Sets the format option to \a opt.
927 
928     \sa testOption()
929 */
930 
setOption(QGL::FormatOptions opt)931 void QGLFormat::setOption(QGL::FormatOptions opt)
932 {
933     detach();
934     if (opt & 0xffff)
935         d->opts |= opt;
936     else
937        d->opts &= ~(opt >> 16);
938 }
939 
940 
941 
942 /*!
943     Returns \c true if format option \a opt is set; otherwise returns \c false.
944 
945     \sa setOption()
946 */
947 
testOption(QGL::FormatOptions opt) const948 bool QGLFormat::testOption(QGL::FormatOptions opt) const
949 {
950     if (opt & 0xffff)
951        return (d->opts & opt) != 0;
952     else
953        return (d->opts & (opt >> 16)) == 0;
954 }
955 
956 /*!
957     Set the minimum depth buffer size to \a size.
958 
959     \sa depthBufferSize(), setDepth(), depth()
960 */
setDepthBufferSize(int size)961 void QGLFormat::setDepthBufferSize(int size)
962 {
963     detach();
964     if (size < 0) {
965         qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
966         return;
967     }
968     d->depthSize = size;
969     setDepth(size > 0);
970 }
971 
972 /*!
973     Returns the depth buffer size.
974 
975     \sa depth(), setDepth(), setDepthBufferSize()
976 */
depthBufferSize() const977 int QGLFormat::depthBufferSize() const
978 {
979    return d->depthSize;
980 }
981 
982 /*!
983     \since 4.2
984 
985     Set the preferred red buffer size to \a size.
986 
987     \sa setGreenBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
988 */
setRedBufferSize(int size)989 void QGLFormat::setRedBufferSize(int size)
990 {
991     detach();
992     if (size < 0) {
993         qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
994         return;
995     }
996     d->redSize = size;
997 }
998 
999 /*!
1000     \since 4.2
1001 
1002     Returns the red buffer size.
1003 
1004     \sa setRedBufferSize()
1005 */
redBufferSize() const1006 int QGLFormat::redBufferSize() const
1007 {
1008    return d->redSize;
1009 }
1010 
1011 /*!
1012     \since 4.2
1013 
1014     Set the preferred green buffer size to \a size.
1015 
1016     \sa setRedBufferSize(), setBlueBufferSize(), setAlphaBufferSize()
1017 */
setGreenBufferSize(int size)1018 void QGLFormat::setGreenBufferSize(int size)
1019 {
1020     detach();
1021     if (size < 0) {
1022         qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
1023         return;
1024     }
1025     d->greenSize = size;
1026 }
1027 
1028 /*!
1029     \since 4.2
1030 
1031     Returns the green buffer size.
1032 
1033     \sa setGreenBufferSize()
1034 */
greenBufferSize() const1035 int QGLFormat::greenBufferSize() const
1036 {
1037    return d->greenSize;
1038 }
1039 
1040 /*!
1041     \since 4.2
1042 
1043     Set the preferred blue buffer size to \a size.
1044 
1045     \sa setRedBufferSize(), setGreenBufferSize(), setAlphaBufferSize()
1046 */
setBlueBufferSize(int size)1047 void QGLFormat::setBlueBufferSize(int size)
1048 {
1049     detach();
1050     if (size < 0) {
1051         qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
1052         return;
1053     }
1054     d->blueSize = size;
1055 }
1056 
1057 /*!
1058     \since 4.2
1059 
1060     Returns the blue buffer size.
1061 
1062     \sa setBlueBufferSize()
1063 */
blueBufferSize() const1064 int QGLFormat::blueBufferSize() const
1065 {
1066    return d->blueSize;
1067 }
1068 
1069 /*!
1070     Set the preferred alpha buffer size to \a size.
1071     This function implicitly enables the alpha channel.
1072 
1073     \sa setRedBufferSize(), setGreenBufferSize(), alphaBufferSize()
1074 */
setAlphaBufferSize(int size)1075 void QGLFormat::setAlphaBufferSize(int size)
1076 {
1077     detach();
1078     if (size < 0) {
1079         qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
1080         return;
1081     }
1082     d->alphaSize = size;
1083     setAlpha(size > 0);
1084 }
1085 
1086 /*!
1087     Returns the alpha buffer size.
1088 
1089     \sa alpha(), setAlpha(), setAlphaBufferSize()
1090 */
alphaBufferSize() const1091 int QGLFormat::alphaBufferSize() const
1092 {
1093    return d->alphaSize;
1094 }
1095 
1096 /*!
1097     Set the preferred accumulation buffer size, where \a size is the
1098     bit depth for each RGBA component.
1099 
1100     \sa accum(), setAccum(), accumBufferSize()
1101 */
setAccumBufferSize(int size)1102 void QGLFormat::setAccumBufferSize(int size)
1103 {
1104     detach();
1105     if (size < 0) {
1106         qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
1107         return;
1108     }
1109     d->accumSize = size;
1110     setAccum(size > 0);
1111 }
1112 
1113 /*!
1114     Returns the accumulation buffer size.
1115 
1116     \sa setAccumBufferSize(), accum(), setAccum()
1117 */
accumBufferSize() const1118 int QGLFormat::accumBufferSize() const
1119 {
1120    return d->accumSize;
1121 }
1122 
1123 /*!
1124     Set the preferred stencil buffer size to \a size.
1125 
1126     \sa stencilBufferSize(), setStencil(), stencil()
1127 */
setStencilBufferSize(int size)1128 void QGLFormat::setStencilBufferSize(int size)
1129 {
1130     detach();
1131     if (size < 0) {
1132         qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
1133         return;
1134     }
1135     d->stencilSize = size;
1136     setStencil(size > 0);
1137 }
1138 
1139 /*!
1140     Returns the stencil buffer size.
1141 
1142     \sa stencil(), setStencil(), setStencilBufferSize()
1143 */
stencilBufferSize() const1144 int QGLFormat::stencilBufferSize() const
1145 {
1146    return d->stencilSize;
1147 }
1148 
1149 /*!
1150     \since 4.7
1151 
1152     Set the OpenGL version to the \a major and \a minor numbers. If a
1153     context compatible with the requested OpenGL version cannot be
1154     created, a context compatible with version 1.x is created instead.
1155 
1156     \sa majorVersion(), minorVersion()
1157 */
setVersion(int major,int minor)1158 void QGLFormat::setVersion(int major, int minor)
1159 {
1160     if (major < 1 || minor < 0) {
1161         qWarning("QGLFormat::setVersion: Cannot set zero or negative version number %d.%d", major, minor);
1162         return;
1163     }
1164     detach();
1165     d->majorVersion = major;
1166     d->minorVersion = minor;
1167 }
1168 
1169 /*!
1170     \since 4.7
1171 
1172     Returns the OpenGL major version.
1173 
1174     \sa setVersion(), minorVersion()
1175 */
majorVersion() const1176 int QGLFormat::majorVersion() const
1177 {
1178     return d->majorVersion;
1179 }
1180 
1181 /*!
1182     \since 4.7
1183 
1184     Returns the OpenGL minor version.
1185 
1186     \sa setVersion(), majorVersion()
1187 */
minorVersion() const1188 int QGLFormat::minorVersion() const
1189 {
1190     return d->minorVersion;
1191 }
1192 
1193 /*!
1194     \enum QGLFormat::OpenGLContextProfile
1195     \since 4.7
1196 
1197     This enum describes the OpenGL context profiles that can be
1198     specified for contexts implementing OpenGL version 3.2 or
1199     higher. These profiles are different from OpenGL ES profiles.
1200 
1201     \value NoProfile            OpenGL version is lower than 3.2.
1202     \value CoreProfile          Functionality deprecated in OpenGL version 3.0 is not available.
1203     \value CompatibilityProfile Functionality from earlier OpenGL versions is available.
1204 */
1205 
1206 /*!
1207     \since 4.7
1208 
1209     Set the OpenGL context profile to \a profile. The \a profile is
1210     ignored if the requested OpenGL version is less than 3.2.
1211 
1212     \sa profile()
1213 */
setProfile(OpenGLContextProfile profile)1214 void QGLFormat::setProfile(OpenGLContextProfile profile)
1215 {
1216     detach();
1217     d->profile = profile;
1218 }
1219 
1220 /*!
1221     \since 4.7
1222 
1223     Returns the OpenGL context profile.
1224 
1225     \sa setProfile()
1226 */
profile() const1227 QGLFormat::OpenGLContextProfile QGLFormat::profile() const
1228 {
1229     return d->profile;
1230 }
1231 
1232 
1233 /*!
1234     \fn bool QGLFormat::hasOpenGL()
1235 
1236     Returns \c true if the window system has any OpenGL support;
1237     otherwise returns \c false.
1238 
1239     \warning This function must not be called until the QApplication
1240     object has been created.
1241 */
hasOpenGL()1242 bool QGLFormat::hasOpenGL()
1243 {
1244     return QApplicationPrivate::platformIntegration()
1245             ->hasCapability(QPlatformIntegration::OpenGL);
1246 }
1247 
1248 /*!
1249     \fn bool QGLFormat::hasOpenGLOverlays()
1250 
1251     Returns \c true if the window system supports OpenGL overlays;
1252     otherwise returns \c false.
1253 
1254     \warning This function must not be called until the QApplication
1255     object has been created.
1256 */
hasOpenGLOverlays()1257 bool QGLFormat::hasOpenGLOverlays()
1258 {
1259     return false;
1260 }
1261 
qOpenGLVersionFlagsFromString(const QString & versionString)1262 QGLFormat::OpenGLVersionFlags Q_AUTOTEST_EXPORT qOpenGLVersionFlagsFromString(const QString &versionString)
1263 {
1264     QGLFormat::OpenGLVersionFlags versionFlags = QGLFormat::OpenGL_Version_None;
1265 
1266     if (versionString.startsWith(QLatin1String("OpenGL ES"))) {
1267         const auto parts = versionString.splitRef(QLatin1Char(' '));
1268         if (parts.size() >= 3) {
1269             if (parts[2].startsWith(QLatin1String("1."))) {
1270                 if (parts[1].endsWith(QLatin1String("-CM"))) {
1271                     versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_0 |
1272                                     QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
1273                     if (parts[2].startsWith(QLatin1String("1.1")))
1274                         versionFlags |= QGLFormat::OpenGL_ES_Common_Version_1_1 |
1275                                         QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
1276                 } else {
1277                     // Not -CM, must be CL, CommonLite
1278                     versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
1279                     if (parts[2].startsWith(QLatin1String("1.1")))
1280                         versionFlags |= QGLFormat::OpenGL_ES_CommonLite_Version_1_1;
1281                 }
1282             } else {
1283                 // OpenGL ES version 2.0 or higher
1284                 versionFlags |= QGLFormat::OpenGL_ES_Version_2_0;
1285             }
1286         } else {
1287             // if < 3 parts to the name, it is an unrecognised OpenGL ES
1288             qWarning("Unrecognised OpenGL ES version");
1289         }
1290     } else {
1291         // not ES, regular OpenGL, the version numbers are first in the string
1292         if (versionString.startsWith(QLatin1String("1."))) {
1293             switch (versionString[2].toLatin1()) {
1294             case '5':
1295                 versionFlags |= QGLFormat::OpenGL_Version_1_5;
1296                 Q_FALLTHROUGH();
1297             case '4':
1298                 versionFlags |= QGLFormat::OpenGL_Version_1_4;
1299                 Q_FALLTHROUGH();
1300             case '3':
1301                 versionFlags |= QGLFormat::OpenGL_Version_1_3;
1302                 Q_FALLTHROUGH();
1303             case '2':
1304                 versionFlags |= QGLFormat::OpenGL_Version_1_2;
1305                 Q_FALLTHROUGH();
1306             case '1':
1307                 versionFlags |= QGLFormat::OpenGL_Version_1_1;
1308                 Q_FALLTHROUGH();
1309             default:
1310                 break;
1311             }
1312         } else if (versionString.startsWith(QLatin1String("2."))) {
1313             versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1314                             QGLFormat::OpenGL_Version_1_2 |
1315                             QGLFormat::OpenGL_Version_1_3 |
1316                             QGLFormat::OpenGL_Version_1_4 |
1317                             QGLFormat::OpenGL_Version_1_5 |
1318                             QGLFormat::OpenGL_Version_2_0;
1319             if (versionString[2].toLatin1() == '1')
1320                 versionFlags |= QGLFormat::OpenGL_Version_2_1;
1321         } else if (versionString.startsWith(QLatin1String("3."))) {
1322             versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1323                             QGLFormat::OpenGL_Version_1_2 |
1324                             QGLFormat::OpenGL_Version_1_3 |
1325                             QGLFormat::OpenGL_Version_1_4 |
1326                             QGLFormat::OpenGL_Version_1_5 |
1327                             QGLFormat::OpenGL_Version_2_0 |
1328                             QGLFormat::OpenGL_Version_2_1 |
1329                             QGLFormat::OpenGL_Version_3_0;
1330             switch (versionString[2].toLatin1()) {
1331             case '3':
1332                 versionFlags |= QGLFormat::OpenGL_Version_3_3;
1333                 Q_FALLTHROUGH();
1334             case '2':
1335                 versionFlags |= QGLFormat::OpenGL_Version_3_2;
1336                 Q_FALLTHROUGH();
1337             case '1':
1338                 versionFlags |= QGLFormat::OpenGL_Version_3_1;
1339                 Q_FALLTHROUGH();
1340             case '0':
1341                 break;
1342             default:
1343                 versionFlags |= QGLFormat::OpenGL_Version_3_1 |
1344                                 QGLFormat::OpenGL_Version_3_2 |
1345                                 QGLFormat::OpenGL_Version_3_3;
1346                 break;
1347             }
1348         } else if (versionString.startsWith(QLatin1String("4."))) {
1349             versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1350                             QGLFormat::OpenGL_Version_1_2 |
1351                             QGLFormat::OpenGL_Version_1_3 |
1352                             QGLFormat::OpenGL_Version_1_4 |
1353                             QGLFormat::OpenGL_Version_1_5 |
1354                             QGLFormat::OpenGL_Version_2_0 |
1355                             QGLFormat::OpenGL_Version_2_1 |
1356                             QGLFormat::OpenGL_Version_3_0 |
1357                             QGLFormat::OpenGL_Version_3_1 |
1358                             QGLFormat::OpenGL_Version_3_2 |
1359                             QGLFormat::OpenGL_Version_3_3 |
1360                             QGLFormat::OpenGL_Version_4_0;
1361             switch (versionString[2].toLatin1()) {
1362             case '3':
1363                 versionFlags |= QGLFormat::OpenGL_Version_4_3;
1364                 Q_FALLTHROUGH();
1365             case '2':
1366                 versionFlags |= QGLFormat::OpenGL_Version_4_2;
1367                 Q_FALLTHROUGH();
1368             case '1':
1369                 versionFlags |= QGLFormat::OpenGL_Version_4_1;
1370                 Q_FALLTHROUGH();
1371             case '0':
1372                 break;
1373             default:
1374                 versionFlags |= QGLFormat::OpenGL_Version_4_1 |
1375                                 QGLFormat::OpenGL_Version_4_2 |
1376                                 QGLFormat::OpenGL_Version_4_3;
1377                 break;
1378             }
1379         } else {
1380             versionFlags |= QGLFormat::OpenGL_Version_1_1 |
1381                             QGLFormat::OpenGL_Version_1_2 |
1382                             QGLFormat::OpenGL_Version_1_3 |
1383                             QGLFormat::OpenGL_Version_1_4 |
1384                             QGLFormat::OpenGL_Version_1_5 |
1385                             QGLFormat::OpenGL_Version_2_0 |
1386                             QGLFormat::OpenGL_Version_2_1 |
1387                             QGLFormat::OpenGL_Version_3_0 |
1388                             QGLFormat::OpenGL_Version_3_1 |
1389                             QGLFormat::OpenGL_Version_3_2 |
1390                             QGLFormat::OpenGL_Version_3_3 |
1391                             QGLFormat::OpenGL_Version_4_0 |
1392                             QGLFormat::OpenGL_Version_4_1 |
1393                             QGLFormat::OpenGL_Version_4_2 |
1394                             QGLFormat::OpenGL_Version_4_3;
1395         }
1396     }
1397     return versionFlags;
1398 }
1399 
1400 /*!
1401     \enum QGLFormat::OpenGLVersionFlag
1402     \since 4.2
1403 
1404     This enum describes the various OpenGL versions that are
1405     recognized by Qt. Use the QGLFormat::openGLVersionFlags() function
1406     to identify which versions that are supported at runtime.
1407 
1408     \value OpenGL_Version_None  If no OpenGL is present or if no OpenGL context is current.
1409 
1410     \value OpenGL_Version_1_1  OpenGL version 1.1 or higher is present.
1411 
1412     \value OpenGL_Version_1_2  OpenGL version 1.2 or higher is present.
1413 
1414     \value OpenGL_Version_1_3  OpenGL version 1.3 or higher is present.
1415 
1416     \value OpenGL_Version_1_4  OpenGL version 1.4 or higher is present.
1417 
1418     \value OpenGL_Version_1_5  OpenGL version 1.5 or higher is present.
1419 
1420     \value OpenGL_Version_2_0  OpenGL version 2.0 or higher is present.
1421     Note that version 2.0 supports all the functionality of version 1.5.
1422 
1423     \value OpenGL_Version_2_1  OpenGL version 2.1 or higher is present.
1424 
1425     \value OpenGL_Version_3_0  OpenGL version 3.0 or higher is present.
1426 
1427     \value OpenGL_Version_3_1  OpenGL version 3.1 or higher is present.
1428     Note that OpenGL version 3.1 or higher does not necessarily support all the features of
1429     version 3.0 and lower.
1430 
1431     \value OpenGL_Version_3_2  OpenGL version 3.2 or higher is present.
1432 
1433     \value OpenGL_Version_3_3  OpenGL version 3.3 or higher is present.
1434 
1435     \value OpenGL_Version_4_0  OpenGL version 4.0 or higher is present.
1436 
1437     \value OpenGL_Version_4_1  OpenGL version 4.1 or higher is present.
1438 
1439     \value OpenGL_Version_4_2  OpenGL version 4.2 or higher is present.
1440 
1441     \value OpenGL_Version_4_3  OpenGL version 4.3 or higher is present.
1442 
1443     \value OpenGL_ES_CommonLite_Version_1_0  OpenGL ES version 1.0 Common Lite or higher is present.
1444 
1445     \value OpenGL_ES_Common_Version_1_0  OpenGL ES version 1.0 Common or higher is present.
1446     The Common profile supports all the features of Common Lite.
1447 
1448     \value OpenGL_ES_CommonLite_Version_1_1  OpenGL ES version 1.1 Common Lite or higher is present.
1449 
1450     \value OpenGL_ES_Common_Version_1_1  OpenGL ES version 1.1 Common or higher is present.
1451     The Common profile supports all the features of Common Lite.
1452 
1453     \value OpenGL_ES_Version_2_0  OpenGL ES version 2.0 or higher is present.
1454     Note that OpenGL ES version 2.0 does not support all the features of OpenGL ES 1.x.
1455     So if OpenGL_ES_Version_2_0 is returned, none of the ES 1.x flags are returned.
1456 
1457     See also \l{http://www.opengl.org} for more information about the different
1458     revisions of OpenGL.
1459 
1460     \sa openGLVersionFlags()
1461 */
1462 
1463 /*!
1464     \since 4.2
1465 
1466     Identifies, at runtime, which OpenGL versions that are supported
1467     by the current platform.
1468 
1469     Note that if OpenGL version 1.5 is supported, its predecessors
1470     (i.e., version 1.4 and lower) are also supported. To identify the
1471     support of a particular feature, like multi texturing, test for
1472     the version in which the feature was first introduced (i.e.,
1473     version 1.3 in the case of multi texturing) to adapt to the largest
1474     possible group of runtime platforms.
1475 
1476     This function needs a valid current OpenGL context to work;
1477     otherwise it will return OpenGL_Version_None.
1478 
1479     \sa hasOpenGL(), hasOpenGLOverlays()
1480 */
openGLVersionFlags()1481 QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
1482 {
1483     static bool cachedDefault = false;
1484     static OpenGLVersionFlags defaultVersionFlags = OpenGL_Version_None;
1485     QGLContext *currentCtx = const_cast<QGLContext *>(QGLContext::currentContext());
1486     QGLTemporaryContext *tmpContext = 0;
1487 
1488     if (currentCtx && currentCtx->d_func()->version_flags_cached)
1489         return currentCtx->d_func()->version_flags;
1490 
1491     if (!currentCtx) {
1492         if (cachedDefault) {
1493             return defaultVersionFlags;
1494         } else {
1495             if (!hasOpenGL())
1496                 return defaultVersionFlags;
1497             tmpContext = new QGLTemporaryContext;
1498             cachedDefault = true;
1499         }
1500     }
1501 
1502     QString versionString(QLatin1String(reinterpret_cast<const char*>(qgl_functions()->glGetString(GL_VERSION))));
1503     OpenGLVersionFlags versionFlags = qOpenGLVersionFlagsFromString(versionString);
1504     if (currentCtx) {
1505         currentCtx->d_func()->version_flags_cached = true;
1506         currentCtx->d_func()->version_flags = versionFlags;
1507     }
1508     if (tmpContext) {
1509         defaultVersionFlags = versionFlags;
1510         delete tmpContext;
1511     }
1512 
1513     return versionFlags;
1514 }
1515 
1516 
1517 /*!
1518     Returns the default QGLFormat for the application. All QGLWidget
1519     objects that are created use this format unless another format is
1520     specified, e.g. when they are constructed.
1521 
1522     If no special default format has been set using
1523     setDefaultFormat(), the default format is the same as that created
1524     with QGLFormat().
1525 
1526     \sa setDefaultFormat()
1527 */
1528 
defaultFormat()1529 QGLFormat QGLFormat::defaultFormat()
1530 {
1531     return *qgl_default_format();
1532 }
1533 
1534 /*!
1535     Sets a new default QGLFormat for the application to \a f. For
1536     example, to set single buffering as the default instead of double
1537     buffering, your main() might contain code like this:
1538     \snippet code/src_opengl_qgl.cpp 4
1539 
1540     \sa defaultFormat()
1541 */
1542 
setDefaultFormat(const QGLFormat & f)1543 void QGLFormat::setDefaultFormat(const QGLFormat &f)
1544 {
1545     *qgl_default_format() = f;
1546 }
1547 
1548 
1549 /*!
1550     Returns the default QGLFormat for overlay contexts.
1551 
1552     The default overlay format is:
1553     \list
1554     \li \l{setDoubleBuffer()}{Double buffer:} Disabled.
1555     \li \l{setDepth()}{Depth buffer:} Disabled.
1556     \li \l{setRgba()}{RGBA:} Disabled (i.e., color index enabled).
1557     \li \l{setAlpha()}{Alpha channel:} Disabled.
1558     \li \l{setAccum()}{Accumulator buffer:} Disabled.
1559     \li \l{setStencil()}{Stencil buffer:} Disabled.
1560     \li \l{setStereo()}{Stereo:} Disabled.
1561     \li \l{setDirectRendering()}{Direct rendering:} Enabled.
1562     \li \l{setOverlay()}{Overlay:} Disabled.
1563     \li \l{setSampleBuffers()}{Multisample buffers:} Disabled.
1564     \li \l{setPlane()}{Plane:} 1 (i.e., first overlay plane).
1565     \endlist
1566 
1567     \sa setDefaultFormat()
1568 */
1569 
defaultOverlayFormat()1570 QGLFormat QGLFormat::defaultOverlayFormat()
1571 {
1572     return *defaultOverlayFormatInstance();
1573 }
1574 
1575 /*!
1576     Sets a new default QGLFormat for overlay contexts to \a f. This
1577     format is used whenever a QGLWidget is created with a format that
1578     hasOverlay() enabled.
1579 
1580     For example, to get a double buffered overlay context (if
1581     available), use code like this:
1582 
1583     \snippet code/src_opengl_qgl.cpp 5
1584 
1585     As usual, you can find out after widget creation whether the
1586     underlying OpenGL system was able to provide the requested
1587     specification:
1588 
1589     \snippet code/src_opengl_qgl.cpp 6
1590 
1591     \sa defaultOverlayFormat()
1592 */
1593 
setDefaultOverlayFormat(const QGLFormat & f)1594 void QGLFormat::setDefaultOverlayFormat(const QGLFormat &f)
1595 {
1596     QGLFormat *defaultFormat = defaultOverlayFormatInstance();
1597     *defaultFormat = f;
1598     // Make sure the user doesn't request that the overlays themselves
1599     // have overlays, since it is unlikely that the system supports
1600     // infinitely many planes...
1601     defaultFormat->setOverlay(false);
1602 }
1603 
1604 
1605 /*!
1606     Returns \c true if all the options of the two QGLFormat objects
1607     \a a and \a b are equal; otherwise returns \c false.
1608 
1609     \relates QGLFormat
1610 */
1611 
operator ==(const QGLFormat & a,const QGLFormat & b)1612 bool operator==(const QGLFormat& a, const QGLFormat& b)
1613 {
1614     return (a.d == b.d) || ((int) a.d->opts == (int) b.d->opts
1615         && a.d->pln == b.d->pln
1616         && a.d->alphaSize == b.d->alphaSize
1617         && a.d->accumSize == b.d->accumSize
1618         && a.d->stencilSize == b.d->stencilSize
1619         && a.d->depthSize == b.d->depthSize
1620         && a.d->redSize == b.d->redSize
1621         && a.d->greenSize == b.d->greenSize
1622         && a.d->blueSize == b.d->blueSize
1623         && a.d->numSamples == b.d->numSamples
1624         && a.d->swapInterval == b.d->swapInterval
1625         && a.d->majorVersion == b.d->majorVersion
1626         && a.d->minorVersion == b.d->minorVersion
1627         && a.d->profile == b.d->profile);
1628 }
1629 
1630 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QGLFormat & f)1631 QDebug operator<<(QDebug dbg, const QGLFormat &f)
1632 {
1633     const QGLFormatPrivate * const d = f.d;
1634 
1635     QDebugStateSaver saver(dbg);
1636     dbg.nospace() << "QGLFormat("
1637                   << "options " << d->opts
1638                   << ", plane " << d->pln
1639                   << ", depthBufferSize " << d->depthSize
1640                   << ", accumBufferSize " << d->accumSize
1641                   << ", stencilBufferSize " << d->stencilSize
1642                   << ", redBufferSize " << d->redSize
1643                   << ", greenBufferSize " << d->greenSize
1644                   << ", blueBufferSize " << d->blueSize
1645                   << ", alphaBufferSize " << d->alphaSize
1646                   << ", samples " << d->numSamples
1647                   << ", swapInterval " << d->swapInterval
1648                   << ", majorVersion " << d->majorVersion
1649                   << ", minorVersion " << d->minorVersion
1650                   << ", profile " << d->profile
1651                   << ')';
1652 
1653     return dbg;
1654 }
1655 #endif
1656 
1657 
1658 /*!
1659     Returns \c false if all the options of the two QGLFormat objects
1660     \a a and \a b are equal; otherwise returns \c true.
1661 
1662     \relates QGLFormat
1663 */
1664 
operator !=(const QGLFormat & a,const QGLFormat & b)1665 bool operator!=(const QGLFormat& a, const QGLFormat& b)
1666 {
1667     return !(a == b);
1668 }
1669 
1670 struct QGLContextGroupList {
appendQGLContextGroupList1671     void append(QGLContextGroup *group) {
1672         QMutexLocker locker(&m_mutex);
1673         m_list.append(group);
1674     }
1675 
removeQGLContextGroupList1676     void remove(QGLContextGroup *group) {
1677         QMutexLocker locker(&m_mutex);
1678         m_list.removeOne(group);
1679     }
1680 
1681     QList<QGLContextGroup *> m_list;
1682     QRecursiveMutex m_mutex;
1683 };
1684 
Q_GLOBAL_STATIC(QGLContextGroupList,qt_context_groups)1685 Q_GLOBAL_STATIC(QGLContextGroupList, qt_context_groups)
1686 
1687 /*****************************************************************************
1688   QGLContext implementation
1689  *****************************************************************************/
1690 
1691 QGLContextGroup::QGLContextGroup(const QGLContext *context)
1692     : m_context(context), m_refs(1)
1693 {
1694     qt_context_groups()->append(this);
1695 }
1696 
~QGLContextGroup()1697 QGLContextGroup::~QGLContextGroup()
1698 {
1699     qt_context_groups()->remove(this);
1700 }
1701 
qt_gl_transfer_context(const QGLContext * ctx)1702 const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
1703 {
1704     if (!ctx)
1705         return 0;
1706     QList<const QGLContext *> shares
1707         (QGLContextPrivate::contextGroup(ctx)->shares());
1708     if (shares.size() >= 2)
1709         return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0);
1710     else
1711         return 0;
1712 }
1713 
QGLContextPrivate(QGLContext * context)1714 QGLContextPrivate::QGLContextPrivate(QGLContext *context)
1715     : internal_context(false)
1716     , q_ptr(context)
1717     , texture_destroyer(0)
1718     , functions(0)
1719 {
1720     group = new QGLContextGroup(context);
1721 
1722     texture_destroyer = new QGLTextureDestroyer;
1723 }
1724 
~QGLContextPrivate()1725 QGLContextPrivate::~QGLContextPrivate()
1726 {
1727     delete functions;
1728 
1729     if (!group->m_refs.deref()) {
1730         Q_ASSERT(group->context() == q_ptr);
1731         delete group;
1732     }
1733 
1734     delete texture_destroyer;
1735 }
1736 
init(QPaintDevice * dev,const QGLFormat & format)1737 void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
1738 {
1739     Q_Q(QGLContext);
1740     glFormat = reqFormat = format;
1741     valid = false;
1742     q->setDevice(dev);
1743 
1744     guiGlContext = 0;
1745     ownContext = false;
1746     fbo = 0;
1747     crWin = false;
1748     initDone = false;
1749     sharing = false;
1750     max_texture_size = -1;
1751     version_flags_cached = false;
1752     version_flags = QGLFormat::OpenGL_Version_None;
1753     current_fbo = 0;
1754     default_fbo = 0;
1755     active_engine = 0;
1756     workaround_needsFullClearOnEveryFrame = false;
1757     workaround_brokenFBOReadBack = false;
1758     workaround_brokenTexSubImage = false;
1759     workaroundsCached = false;
1760 
1761     workaround_brokenTextureFromPixmap = false;
1762     workaround_brokenTextureFromPixmap_init = false;
1763 
1764     workaround_brokenAlphaTexSubImage = false;
1765     workaround_brokenAlphaTexSubImage_init = false;
1766 
1767     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
1768         vertexAttributeArraysEnabledState[i] = false;
1769 }
1770 
1771 QGLContext* QGLContext::currentCtx = 0;
1772 
1773 /*
1774     QGLTemporaryContext implementation
1775 */
1776 class QGLTemporaryContextPrivate
1777 {
1778 public:
1779     QWindow *window;
1780     QOpenGLContext *context;
1781 
1782     QGLContext *oldContext;
1783 };
1784 
QGLTemporaryContext(bool,QWidget *)1785 QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *)
1786     : d(new QGLTemporaryContextPrivate)
1787 {
1788     d->oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
1789 
1790     d->window = new QWindow;
1791     d->window->setSurfaceType(QWindow::OpenGLSurface);
1792     d->window->setGeometry(QRect(0, 0, 3, 3));
1793     d->window->create();
1794 
1795     d->context = new QOpenGLContext;
1796 #if !defined(QT_OPENGL_ES)
1797     if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
1798         // On desktop, request latest released version
1799         QSurfaceFormat format;
1800 #if defined(Q_OS_MAC)
1801         // OS X is limited to OpenGL 3.2 Core Profile at present
1802         // so set that here. If we use compatibility profile it
1803         // only reports 2.x contexts.
1804         format.setMajorVersion(3);
1805         format.setMinorVersion(2);
1806         format.setProfile(QSurfaceFormat::CoreProfile);
1807 #else
1808         format.setMajorVersion(4);
1809         format.setMinorVersion(3);
1810 #endif
1811         d->context->setFormat(format);
1812     }
1813 #endif // QT_OPENGL_ES
1814     d->context->create();
1815     d->context->makeCurrent(d->window);
1816 }
1817 
~QGLTemporaryContext()1818 QGLTemporaryContext::~QGLTemporaryContext()
1819 {
1820     if (d->oldContext)
1821         d->oldContext->makeCurrent();
1822 
1823     delete d->context;
1824     delete d->window;
1825 }
1826 
1827 /*
1828    Read back the contents of the currently bound framebuffer, used in
1829    QGLWidget::grabFrameBuffer(), QGLPixelbuffer::toImage() and
1830    QGLFramebufferObject::toImage()
1831 */
1832 
convertFromGLImage(QImage & img,int w,int h,bool alpha_format,bool include_alpha)1833 static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
1834 {
1835     Q_ASSERT(!img.isNull());
1836     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
1837         // OpenGL gives RGBA; Qt wants ARGB
1838         uint *p = (uint*)img.bits();
1839         uint *end = p + w*h;
1840         if (alpha_format && include_alpha) {
1841             while (p < end) {
1842                 uint a = *p << 24;
1843                 *p = (*p >> 8) | a;
1844                 p++;
1845             }
1846         } else {
1847             // This is an old legacy fix for PowerPC based Macs, which
1848             // we shouldn't remove
1849             while (p < end) {
1850                 *p = 0xff000000 | (*p>>8);
1851                 ++p;
1852             }
1853         }
1854     } else {
1855         // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
1856         for (int y = 0; y < h; y++) {
1857             uint *q = (uint*)img.scanLine(y);
1858             for (int x=0; x < w; ++x) {
1859                 const uint pixel = *q;
1860                 if (alpha_format && include_alpha) {
1861                     *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff)
1862                          | (pixel & 0xff00ff00);
1863                 } else {
1864                     *q = 0xff000000 | ((pixel << 16) & 0xff0000)
1865                          | ((pixel >> 16) & 0xff) | (pixel & 0x00ff00);
1866                 }
1867 
1868                 q++;
1869             }
1870         }
1871 
1872     }
1873     img = img.mirrored();
1874 }
1875 
qt_gl_read_frame_buffer(const QSize & size,bool alpha_format,bool include_alpha)1876 QImage qt_gl_read_frame_buffer(const QSize &size, bool alpha_format, bool include_alpha)
1877 {
1878     QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied
1879                                                      : QImage::Format_RGB32);
1880     if (img.isNull())
1881         return QImage();
1882     int w = size.width();
1883     int h = size.height();
1884     qgl_functions()->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1885     convertFromGLImage(img, w, h, alpha_format, include_alpha);
1886     return img;
1887 }
1888 
qt_gl_read_texture(const QSize & size,bool alpha_format,bool include_alpha)1889 QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha)
1890 {
1891     QImage img(size, alpha_format ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
1892     if (img.isNull())
1893         return QImage();
1894     int w = size.width();
1895     int h = size.height();
1896 #ifndef QT_OPENGL_ES
1897     if (!QOpenGLContext::currentContext()->isOpenGLES()) {
1898 
1899         qgl1_functions()->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1900     }
1901 #endif // QT_OPENGL_ES
1902     convertFromGLImage(img, w, h, alpha_format, include_alpha);
1903     return img;
1904 }
1905 
Q_GLOBAL_STATIC(QGLTextureCache,qt_gl_texture_cache)1906 Q_GLOBAL_STATIC(QGLTextureCache, qt_gl_texture_cache)
1907 
1908 QGLTextureCache::QGLTextureCache()
1909     : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
1910 {
1911     QImagePixmapCleanupHooks::instance()->addPlatformPixmapModificationHook(cleanupTexturesForPixampData);
1912     QImagePixmapCleanupHooks::instance()->addPlatformPixmapDestructionHook(cleanupBeforePixmapDestruction);
1913     QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey);
1914 }
1915 
~QGLTextureCache()1916 QGLTextureCache::~QGLTextureCache()
1917 {
1918     QImagePixmapCleanupHooks::instance()->removePlatformPixmapModificationHook(cleanupTexturesForPixampData);
1919     QImagePixmapCleanupHooks::instance()->removePlatformPixmapDestructionHook(cleanupBeforePixmapDestruction);
1920     QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey);
1921 }
1922 
insert(QGLContext * ctx,qint64 key,QGLTexture * texture,int cost)1923 void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
1924 {
1925     QWriteLocker locker(&m_lock);
1926     const QGLTextureCacheKey cacheKey = {key, QGLContextPrivate::contextGroup(ctx)};
1927     const bool inserted = m_cache.insert(cacheKey, texture, cost);
1928     Q_UNUSED(inserted) Q_ASSERT(inserted);
1929 }
1930 
remove(qint64 key)1931 void QGLTextureCache::remove(qint64 key)
1932 {
1933     QWriteLocker locker(&m_lock);
1934     QMutexLocker groupLocker(&qt_context_groups()->m_mutex);
1935     QList<QGLContextGroup *>::const_iterator it = qt_context_groups()->m_list.constBegin();
1936     while (it != qt_context_groups()->m_list.constEnd()) {
1937         const QGLTextureCacheKey cacheKey = {key, *it};
1938         m_cache.remove(cacheKey);
1939         ++it;
1940     }
1941 }
1942 
remove(QGLContext * ctx,GLuint textureId)1943 bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId)
1944 {
1945     QWriteLocker locker(&m_lock);
1946     QList<QGLTextureCacheKey> keys = m_cache.keys();
1947     for (int i = 0; i < keys.size(); ++i) {
1948         QGLTexture *tex = m_cache.object(keys.at(i));
1949         if (tex->id == textureId && tex->context == ctx) {
1950             tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call
1951             m_cache.remove(keys.at(i));
1952             return true;
1953         }
1954     }
1955     return false;
1956 }
1957 
removeContextTextures(QGLContext * ctx)1958 void QGLTextureCache::removeContextTextures(QGLContext* ctx)
1959 {
1960     QWriteLocker locker(&m_lock);
1961     QList<QGLTextureCacheKey> keys = m_cache.keys();
1962     for (int i = 0; i < keys.size(); ++i) {
1963         const QGLTextureCacheKey &key = keys.at(i);
1964         if (m_cache.object(key)->context == ctx)
1965             m_cache.remove(key);
1966     }
1967 }
1968 
1969 /*
1970   a hook that removes textures from the cache when a pixmap/image
1971   is deref'ed
1972 */
cleanupTexturesForCacheKey(qint64 cacheKey)1973 void QGLTextureCache::cleanupTexturesForCacheKey(qint64 cacheKey)
1974 {
1975     qt_gl_texture_cache()->remove(cacheKey);
1976 }
1977 
1978 
cleanupTexturesForPixampData(QPlatformPixmap * pmd)1979 void QGLTextureCache::cleanupTexturesForPixampData(QPlatformPixmap* pmd)
1980 {
1981     cleanupTexturesForCacheKey(pmd->cacheKey());
1982 }
1983 
cleanupBeforePixmapDestruction(QPlatformPixmap * pmd)1984 void QGLTextureCache::cleanupBeforePixmapDestruction(QPlatformPixmap* pmd)
1985 {
1986     // Remove any bound textures first:
1987     cleanupTexturesForPixampData(pmd);
1988 }
1989 
instance()1990 QGLTextureCache *QGLTextureCache::instance()
1991 {
1992     return qt_gl_texture_cache();
1993 }
1994 
1995 // DDS format structure
1996 struct DDSFormat {
1997     quint32 dwSize;
1998     quint32 dwFlags;
1999     quint32 dwHeight;
2000     quint32 dwWidth;
2001     quint32 dwLinearSize;
2002     quint32 dummy1;
2003     quint32 dwMipMapCount;
2004     quint32 dummy2[11];
2005     struct {
2006         quint32 dummy3[2];
2007         quint32 dwFourCC;
2008         quint32 dummy4[5];
2009     } ddsPixelFormat;
2010 };
2011 
2012 // compressed texture pixel formats
2013 #define FOURCC_DXT1  0x31545844
2014 #define FOURCC_DXT2  0x32545844
2015 #define FOURCC_DXT3  0x33545844
2016 #define FOURCC_DXT4  0x34545844
2017 #define FOURCC_DXT5  0x35545844
2018 
2019 // ####TODO Properly #ifdef this class to use #define symbols actually defined
2020 // by system GL includes
2021 #ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT
2022 #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0
2023 #endif
2024 
2025 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
2026 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1
2027 #endif
2028 
2029 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
2030 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
2031 #endif
2032 
2033 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
2034 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
2035 #endif
2036 
2037 #ifndef GL_GENERATE_MIPMAP_SGIS
2038 #define GL_GENERATE_MIPMAP_SGIS       0x8191
2039 #define GL_GENERATE_MIPMAP_HINT_SGIS  0x8192
2040 #endif
2041 
2042 /*!
2043     \class QGLContext
2044     \inmodule QtOpenGL
2045     \obsolete
2046 
2047     \brief The QGLContext class encapsulates an OpenGL rendering context.
2048 
2049     An OpenGL rendering context is a complete set of OpenGL state
2050     variables. The rendering context's \l {QGL::FormatOption} {format}
2051     is set in the constructor, but it can also be set later with
2052     setFormat(). The format options that are actually set are returned
2053     by format(); the options you asked for are returned by
2054     requestedFormat(). Note that after a QGLContext object has been
2055     constructed, the actual OpenGL context must be created by
2056     explicitly calling the \l{create()}
2057     function. The makeCurrent() function makes this context the
2058     current rendering context. You can make \e no context current
2059     using doneCurrent(). The reset() function will reset the context
2060     and make it invalid.
2061 
2062     You can examine properties of the context with, e.g. isValid(),
2063     isSharing(), initialized(), windowCreated() and
2064     overlayTransparentColor().
2065 
2066     If you're using double buffering you can swap the screen contents
2067     with the off-screen buffer using swapBuffers().
2068 
2069     Please note that QGLContext is not thread safe.
2070 */
2071 
2072 /*!
2073     \enum QGLContext::BindOption
2074     \since 4.6
2075 
2076     A set of options to decide how to bind a texture using bindTexture().
2077 
2078     \value NoBindOption Don't do anything, pass the texture straight
2079     through.
2080 
2081     \value InvertedYBindOption Specifies that the texture should be flipped
2082     over the X axis so that the texture coordinate 0,0 corresponds to
2083     the top left corner. Inverting the texture implies a deep copy
2084     prior to upload.
2085 
2086     \value MipmapBindOption Specifies that bindTexture() should try
2087     to generate mipmaps.  If the GL implementation supports the \c
2088     GL_SGIS_generate_mipmap extension, mipmaps will be automatically
2089     generated for the texture. Mipmap generation is only supported for
2090     the \c GL_TEXTURE_2D target.
2091 
2092     \value PremultipliedAlphaBindOption Specifies that the image should be
2093     uploaded with premultiplied alpha and does a conversion accordingly.
2094 
2095     \value LinearFilteringBindOption Specifies that the texture filtering
2096     should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is
2097     also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR.
2098 
2099     \value DefaultBindOption In Qt 4.5 and earlier, bindTexture()
2100     would mirror the image and automatically generate mipmaps. This
2101     option helps preserve this default behavior.
2102 
2103     \omitvalue CanFlipNativePixmapBindOption \omit Used by x11 from pixmap to choose
2104     whether or not it can bind the pixmap upside down or not. \endomit
2105 
2106     \omitvalue MemoryManagedBindOption \omit Used by paint engines to
2107     indicate that the pixmap should be memory managed along side with
2108     the pixmap/image that it stems from, e.g. installing destruction
2109     hooks in them. \endomit
2110 
2111     \omitvalue TemporarilyCachedBindOption \omit Used by paint engines on some
2112     platforms to indicate that the pixmap or image texture is possibly
2113     cached only temporarily and must be destroyed immediately after the use. \endomit
2114 
2115     \omitvalue InternalBindOption
2116 */
2117 
2118 /*!
2119     \obsolete
2120 
2121     Constructs an OpenGL context for the given paint \a device, which
2122     can be a widget or a pixmap. The \a format specifies several
2123     display options for the context.
2124 
2125     If the underlying OpenGL/Window system cannot satisfy all the
2126     features requested in \a format, the nearest subset of features
2127     will be used. After creation, the format() method will return the
2128     actual format obtained.
2129 
2130     Note that after a QGLContext object has been constructed, \l
2131     create() must be called explicitly to create the actual OpenGL
2132     context. The context will be \l {isValid()}{invalid} if it was not
2133     possible to obtain a GL context at all.
2134 */
2135 
QGLContext(const QGLFormat & format,QPaintDevice * device)2136 QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
2137     : d_ptr(new QGLContextPrivate(this))
2138 {
2139     Q_D(QGLContext);
2140     d->init(device, format);
2141 }
2142 
2143 /*!
2144     Constructs an OpenGL context with the given \a format which
2145     specifies several display options for the context.
2146 
2147     If the underlying OpenGL/Window system cannot satisfy all the
2148     features requested in \a format, the nearest subset of features
2149     will be used. After creation, the format() method will return the
2150     actual format obtained.
2151 
2152     Note that after a QGLContext object has been constructed, \l
2153     create() must be called explicitly to create the actual OpenGL
2154     context. The context will be \l {isValid()}{invalid} if it was not
2155     possible to obtain a GL context at all.
2156 
2157     \sa format(), isValid()
2158 */
QGLContext(const QGLFormat & format)2159 QGLContext::QGLContext(const QGLFormat &format)
2160     : d_ptr(new QGLContextPrivate(this))
2161 {
2162     Q_D(QGLContext);
2163     d->init(0, format);
2164 }
2165 
qDeleteQGLContext(void * handle)2166 static void qDeleteQGLContext(void *handle)
2167 {
2168     QGLContext *context = static_cast<QGLContext *>(handle);
2169     delete context;
2170 }
2171 
QGLContext(QOpenGLContext * context)2172 QGLContext::QGLContext(QOpenGLContext *context)
2173     : d_ptr(new QGLContextPrivate(this))
2174 {
2175     Q_D(QGLContext);
2176     d->init(0, QGLFormat::fromSurfaceFormat(context->format()));
2177     d->guiGlContext = context;
2178     d->guiGlContext->setQGLContextHandle(this, qDeleteQGLContext);
2179     d->ownContext = false;
2180     d->valid = context->isValid();
2181     d->setupSharing();
2182 }
2183 
2184 /*!
2185     Returns the OpenGL context handle.
2186 */
contextHandle() const2187 QOpenGLContext *QGLContext::contextHandle() const
2188 {
2189     Q_D(const QGLContext);
2190     return d->guiGlContext;
2191 }
2192 
2193 /*!
2194     Returns an OpenGL context for the window context specified by the \a context
2195     parameter.
2196 */
fromOpenGLContext(QOpenGLContext * context)2197 QGLContext *QGLContext::fromOpenGLContext(QOpenGLContext *context)
2198 {
2199     if (!context)
2200         return 0;
2201     if (context->qGLContextHandle()) {
2202         return reinterpret_cast<QGLContext *>(context->qGLContextHandle());
2203     }
2204     QGLContext *glContext = new QGLContext(context);
2205     //Don't call create on context. This can cause the platformFormat to be set on the widget, which
2206     //will cause the platformWindow to be recreated.
2207     return glContext;
2208 }
2209 
2210 /*!
2211     Destroys the OpenGL context and frees its resources.
2212 */
2213 
~QGLContext()2214 QGLContext::~QGLContext()
2215 {
2216     // remove any textures cached in this context
2217     QGLTextureCache::instance()->removeContextTextures(this);
2218 
2219     // clean up resources specific to this context
2220     d_ptr->cleanup();
2221 
2222     QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
2223     reset();
2224 }
2225 
cleanup()2226 void QGLContextPrivate::cleanup()
2227 {
2228 }
2229 
2230 #define ctx q_ptr
setVertexAttribArrayEnabled(int arrayIndex,bool enabled)2231 void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled)
2232 {
2233     Q_Q(QGLContext);
2234     Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT);
2235 #ifdef glEnableVertexAttribArray
2236     Q_ASSERT(glEnableVertexAttribArray);
2237 #endif
2238 
2239     if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled)
2240         q->functions()->glDisableVertexAttribArray(arrayIndex);
2241 
2242     if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled)
2243         q->functions()->glEnableVertexAttribArray(arrayIndex);
2244 
2245     vertexAttributeArraysEnabledState[arrayIndex] = enabled;
2246 }
2247 
syncGlState()2248 void QGLContextPrivate::syncGlState()
2249 {
2250     Q_Q(QGLContext);
2251 #ifdef glEnableVertexAttribArray
2252     Q_ASSERT(glEnableVertexAttribArray);
2253 #endif
2254     for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) {
2255         if (vertexAttributeArraysEnabledState[i])
2256             q->functions()->glEnableVertexAttribArray(i);
2257         else
2258             q->functions()->glDisableVertexAttribArray(i);
2259     }
2260 
2261 }
2262 #undef ctx
2263 
swapRegion(const QRegion &)2264 void QGLContextPrivate::swapRegion(const QRegion &)
2265 {
2266     Q_Q(QGLContext);
2267     q->swapBuffers();
2268 }
2269 
2270 /*!
2271     \overload
2272 
2273     Reads the compressed texture file \a fileName and generates a 2D GL
2274     texture from it.
2275 
2276     This function can load DirectDrawSurface (DDS) textures in the
2277     DXT1, DXT3 and DXT5 DDS formats if the \c GL_ARB_texture_compression
2278     and \c GL_EXT_texture_compression_s3tc extensions are supported.
2279 
2280     Since 4.6.1, textures in the ETC1 format can be loaded if the
2281     \c GL_OES_compressed_ETC1_RGB8_texture extension is supported
2282     and the ETC1 texture has been encapsulated in the PVR container format.
2283     Also, textures in the PVRTC2 and PVRTC4 formats can be loaded
2284     if the \c GL_IMG_texture_compression_pvrtc extension is supported.
2285 
2286     \sa deleteTexture()
2287 */
2288 
bindTexture(const QString & fileName)2289 GLuint QGLContext::bindTexture(const QString &fileName)
2290 {
2291     QGLTexture texture(this);
2292     QSize size = texture.bindCompressedTexture(fileName);
2293     if (!size.isValid())
2294         return 0;
2295     return texture.id;
2296 }
2297 
qt_gl_convertToGLFormatHelper(QRgb src_pixel,GLenum texture_format)2298 static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
2299 {
2300     if (texture_format == GL_BGRA) {
2301         if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2302             return ((src_pixel << 24) & 0xff000000)
2303                    | ((src_pixel >> 24) & 0x000000ff)
2304                    | ((src_pixel << 8) & 0x00ff0000)
2305                    | ((src_pixel >> 8) & 0x0000ff00);
2306         } else {
2307             return src_pixel;
2308         }
2309     } else {  // GL_RGBA
2310         if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2311             return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
2312         } else {
2313             return ((src_pixel << 16) & 0xff0000)
2314                    | ((src_pixel >> 16) & 0xff)
2315                    | (src_pixel & 0xff00ff00);
2316         }
2317     }
2318 }
2319 
convertToGLFormatHelper(QImage & dst,const QImage & img,GLenum texture_format)2320 static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
2321 {
2322     Q_ASSERT(dst.depth() == 32);
2323     Q_ASSERT(img.depth() == 32);
2324 
2325     if (dst.size() != img.size()) {
2326         int target_width = dst.width();
2327         int target_height = dst.height();
2328         qreal sx = target_width / qreal(img.width());
2329         qreal sy = target_height / qreal(img.height());
2330 
2331         quint32 *dest = (quint32 *) dst.scanLine(0); // NB! avoid detach here
2332         const uchar *srcPixels = img.constScanLine(img.height() - 1);
2333         int sbpl = img.bytesPerLine();
2334         int dbpl = dst.bytesPerLine();
2335 
2336         int ix = int(0x00010000 / sx);
2337         int iy = int(0x00010000 / sy);
2338 
2339         quint32 basex = int(0.5 * ix);
2340         quint32 srcy = int(0.5 * iy);
2341 
2342         // scale, swizzle and mirror in one loop
2343         while (target_height--) {
2344             const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
2345             int srcx = basex;
2346             for (int x=0; x<target_width; ++x) {
2347                 dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
2348                 srcx += ix;
2349             }
2350             dest = (quint32 *)(((uchar *) dest) + dbpl);
2351             srcy += iy;
2352         }
2353     } else {
2354         const int width = img.width();
2355         const int height = img.height();
2356         const uint *p = (const uint*) img.scanLine(img.height() - 1);
2357         uint *q = (uint*) dst.scanLine(0);
2358 
2359         if (texture_format == GL_BGRA) {
2360             if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2361                 // mirror + swizzle
2362                 for (int i=0; i < height; ++i) {
2363                     const uint *end = p + width;
2364                     while (p < end) {
2365                         *q = ((*p << 24) & 0xff000000)
2366                              | ((*p >> 24) & 0x000000ff)
2367                              | ((*p << 8) & 0x00ff0000)
2368                              | ((*p >> 8) & 0x0000ff00);
2369                         p++;
2370                         q++;
2371                     }
2372                     p -= 2 * width;
2373                 }
2374             } else {
2375                 const uint bytesPerLine = img.bytesPerLine();
2376                 for (int i=0; i < height; ++i) {
2377                     memcpy(q, p, bytesPerLine);
2378                     q += width;
2379                     p -= width;
2380                 }
2381             }
2382         } else {
2383             if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
2384                 for (int i=0; i < height; ++i) {
2385                     const uint *end = p + width;
2386                     while (p < end) {
2387                         *q = (*p << 8) | ((*p >> 24) & 0xff);
2388                         p++;
2389                         q++;
2390                     }
2391                     p -= 2 * width;
2392                 }
2393             } else {
2394                 for (int i=0; i < height; ++i) {
2395                     const uint *end = p + width;
2396                     while (p < end) {
2397                         *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
2398                         p++;
2399                         q++;
2400                     }
2401                     p -= 2 * width;
2402                 }
2403             }
2404         }
2405     }
2406 }
2407 
2408 /*! \internal */
bindTexture(const QImage & image,GLenum target,GLint format,QGLContext::BindOptions options)2409 QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
2410                                            QGLContext::BindOptions options)
2411 {
2412     Q_Q(QGLContext);
2413 
2414     const qint64 key = image.cacheKey();
2415     QGLTexture *texture = textureCacheLookup(key, target);
2416     if (texture) {
2417         if (image.paintingActive()) {
2418             // A QPainter is active on the image - take the safe route and replace the texture.
2419             q->deleteTexture(texture->id);
2420             texture = 0;
2421         } else {
2422             qgl_functions()->glBindTexture(target, texture->id);
2423             return texture;
2424         }
2425     }
2426 
2427     if (!texture)
2428         texture = bindTexture(image, target, format, key, options);
2429     // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
2430     Q_ASSERT(texture);
2431 
2432     // Enable the cleanup hooks for this image so that the texture cache entry is removed when the
2433     // image gets deleted:
2434     QImagePixmapCleanupHooks::enableCleanupHooks(image);
2435 
2436     return texture;
2437 }
2438 
2439 // #define QGL_BIND_TEXTURE_DEBUG
2440 
2441 // ####TODO Properly #ifdef this file to use #define symbols actually defined
2442 // by OpenGL/ES includes
2443 #ifndef GL_UNSIGNED_INT_8_8_8_8_REV
2444 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
2445 #endif
2446 
2447 // map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout
qgl_byteSwapImage(QImage & img,GLenum pixel_type)2448 static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type)
2449 {
2450     const int width = img.width();
2451     const int height = img.height();
2452 
2453     if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
2454         || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian))
2455     {
2456         for (int i = 0; i < height; ++i) {
2457             uint *p = (uint *) img.scanLine(i);
2458             for (int x = 0; x < width; ++x)
2459                 p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
2460         }
2461     } else {
2462         for (int i = 0; i < height; ++i) {
2463             uint *p = (uint *) img.scanLine(i);
2464             for (int x = 0; x < width; ++x)
2465                 p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
2466         }
2467     }
2468 }
2469 
bindTexture(const QImage & image,GLenum target,GLint internalFormat,const qint64 key,QGLContext::BindOptions options)2470 QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
2471                                            const qint64 key, QGLContext::BindOptions options)
2472 {
2473     Q_Q(QGLContext);
2474     QOpenGLFunctions *funcs = qgl_functions();
2475 
2476 #ifdef QGL_BIND_TEXTURE_DEBUG
2477     printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x, key=%llx\n",
2478            image.width(), image.height(), internalFormat, int(options), key);
2479     QTime time;
2480     time.start();
2481 #endif
2482 
2483 #ifndef QT_NO_DEBUG
2484     // Reset the gl error stack...git
2485     while (funcs->glGetError() != GL_NO_ERROR) ;
2486 #endif
2487 
2488     // Scale the pixmap if needed. GL textures needs to have the
2489     // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
2490     // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
2491     int tx_w = qNextPowerOfTwo(image.width() - 1);
2492     int tx_h = qNextPowerOfTwo(image.height() - 1);
2493 
2494     QImage img = image;
2495 
2496     if (!qgl_extensions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)
2497         && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
2498         && (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
2499     {
2500         img = img.scaled(tx_w, tx_h);
2501 #ifdef QGL_BIND_TEXTURE_DEBUG
2502         printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed());
2503 
2504 #endif
2505     }
2506 
2507     GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST;
2508 
2509     GLuint tx_id;
2510     funcs->glGenTextures(1, &tx_id);
2511     funcs->glBindTexture(target, tx_id);
2512     funcs->glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filtering);
2513 
2514     QOpenGLContext *ctx = QOpenGLContext::currentContext();
2515     bool genMipmap = !ctx->isOpenGLES();
2516     if (glFormat.directRendering()
2517         && (qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::GenerateMipmap))
2518         && target == GL_TEXTURE_2D
2519         && (options & QGLContext::MipmapBindOption))
2520     {
2521 #if !defined(QT_OPENGL_ES_2)
2522         if (genMipmap) {
2523             funcs->glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
2524             funcs->glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2525         } else {
2526             funcs->glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
2527             genMipmap = true;
2528         }
2529 #else
2530         funcs->glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
2531         genMipmap = true;
2532 #endif
2533         funcs->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption
2534                                ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST);
2535 #ifdef QGL_BIND_TEXTURE_DEBUG
2536         printf(" - generating mipmaps (%d ms)\n", time.elapsed());
2537 #endif
2538     } else {
2539         funcs->glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filtering);
2540     }
2541 
2542     QImage::Format target_format = img.format();
2543     bool premul = options & QGLContext::PremultipliedAlphaBindOption;
2544     bool needsbyteswap = true;
2545     GLenum externalFormat;
2546     GLuint pixel_type;
2547     if (target_format == QImage::Format_RGBA8888
2548         || target_format == QImage::Format_RGBA8888_Premultiplied
2549         || target_format == QImage::Format_RGBX8888) {
2550         externalFormat = GL_RGBA;
2551         pixel_type = GL_UNSIGNED_BYTE;
2552         needsbyteswap = false;
2553     } else if (qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) {
2554         externalFormat = GL_BGRA;
2555         needsbyteswap = false;
2556         if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
2557             pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
2558         else
2559             pixel_type = GL_UNSIGNED_BYTE;
2560     } else {
2561         externalFormat = GL_RGBA;
2562         pixel_type = GL_UNSIGNED_BYTE;
2563     }
2564 
2565     switch (target_format) {
2566     case QImage::Format_ARGB32:
2567         if (premul) {
2568             img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied);
2569 #ifdef QGL_BIND_TEXTURE_DEBUG
2570             printf(" - converted ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed());
2571 #endif
2572         }
2573         break;
2574     case QImage::Format_ARGB32_Premultiplied:
2575         if (!premul) {
2576             img = img.convertToFormat(target_format = QImage::Format_ARGB32);
2577 #ifdef QGL_BIND_TEXTURE_DEBUG
2578             printf(" - converted ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
2579 #endif
2580         }
2581         break;
2582     case QImage::Format_RGBA8888:
2583         if (premul) {
2584             img = img.convertToFormat(target_format = QImage::Format_RGBA8888_Premultiplied);
2585 #ifdef QGL_BIND_TEXTURE_DEBUG
2586             printf(" - converted RGBA8888 -> RGBA8888_Premultiplied (%d ms) \n", time.elapsed());
2587 #endif
2588         }
2589         break;
2590     case QImage::Format_RGBA8888_Premultiplied:
2591         if (!premul) {
2592             img = img.convertToFormat(target_format = QImage::Format_RGBA8888);
2593 #ifdef QGL_BIND_TEXTURE_DEBUG
2594             printf(" - converted RGBA8888_Premultiplied -> RGBA8888 (%d ms) \n", time.elapsed());
2595 #endif
2596         }
2597         break;
2598     case QImage::Format_RGB16:
2599         pixel_type = GL_UNSIGNED_SHORT_5_6_5;
2600         externalFormat = GL_RGB;
2601         internalFormat = GL_RGB;
2602         needsbyteswap = false;
2603         break;
2604     case QImage::Format_RGB32:
2605     case QImage::Format_RGBX8888:
2606         break;
2607     default:
2608         // Ideally more formats would be converted directly to an RGBA8888 format,
2609         // but we are only guaranteed to have a fast conversion to an ARGB format.
2610         if (img.hasAlphaChannel()) {
2611             img = img.convertToFormat(premul
2612                                       ? QImage::Format_ARGB32_Premultiplied
2613                                       : QImage::Format_ARGB32);
2614 #ifdef QGL_BIND_TEXTURE_DEBUG
2615             printf(" - converted to 32-bit alpha format (%d ms)\n", time.elapsed());
2616 #endif
2617         } else {
2618             img = img.convertToFormat(QImage::Format_RGB32);
2619 #ifdef QGL_BIND_TEXTURE_DEBUG
2620             printf(" - converted to 32-bit (%d ms)\n", time.elapsed());
2621 #endif
2622         }
2623     }
2624 
2625     if (options & QGLContext::InvertedYBindOption) {
2626         if (img.isDetached()) {
2627             int ipl = img.bytesPerLine() / 4;
2628             int h = img.height();
2629             for (int y=0; y<h/2; ++y) {
2630                 int *a = (int *) img.scanLine(y);
2631                 int *b = (int *) img.scanLine(h - y - 1);
2632                 for (int x=0; x<ipl; ++x)
2633                     qSwap(a[x], b[x]);
2634             }
2635         } else {
2636             // Create a new image and copy across.  If we use the
2637             // above in-place code then a full copy of the image is
2638             // made before the lines are swapped, which processes the
2639             // data twice.  This version should only do it once.
2640             img = img.mirrored();
2641         }
2642 #ifdef QGL_BIND_TEXTURE_DEBUG
2643             printf(" - flipped bits over y (%d ms)\n", time.elapsed());
2644 #endif
2645     }
2646 
2647     if (needsbyteswap) {
2648         // The only case where we end up with a depth different from
2649         // 32 in the switch above is for the RGB16 case, where we do
2650         // not need a byteswap.
2651         Q_ASSERT(img.depth() == 32);
2652         qgl_byteSwapImage(img, pixel_type);
2653 #ifdef QGL_BIND_TEXTURE_DEBUG
2654             printf(" - did byte swapping (%d ms)\n", time.elapsed());
2655 #endif
2656     }
2657     if (ctx->isOpenGLES()) {
2658         // OpenGL/ES requires that the internal and external formats be
2659         // identical.
2660         internalFormat = externalFormat;
2661     }
2662 #ifdef QGL_BIND_TEXTURE_DEBUG
2663     printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
2664            img.format(), externalFormat, internalFormat, pixel_type);
2665 #endif
2666 
2667     const QImage &constRef = img; // to avoid detach in bits()...
2668     funcs->glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
2669                         pixel_type, constRef.bits());
2670     if (genMipmap && ctx->isOpenGLES())
2671         q->functions()->glGenerateMipmap(target);
2672 #ifndef QT_NO_DEBUG
2673     GLenum error = funcs->glGetError();
2674     if (error != GL_NO_ERROR) {
2675         qWarning(" - texture upload failed, error code 0x%x, enum: %d (%x)\n", error, target, target);
2676     }
2677 #endif
2678 
2679 #ifdef QGL_BIND_TEXTURE_DEBUG
2680     static int totalUploadTime = 0;
2681     totalUploadTime += time.elapsed();
2682     printf(" - upload done in %d ms, (accumulated: %d ms)\n", time.elapsed(), totalUploadTime);
2683 #endif
2684 
2685 
2686     // this assumes the size of a texture is always smaller than the max cache size
2687     int cost = img.width()*img.height()*4/1024;
2688     QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
2689     QGLTextureCache::instance()->insert(q, key, texture, cost);
2690 
2691     return texture;
2692 }
2693 
textureCacheLookup(const qint64 key,GLenum target)2694 QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
2695 {
2696     Q_Q(QGLContext);
2697     QGLTexture *texture = QGLTextureCache::instance()->getTexture(q, key);
2698     if (texture && texture->target == target
2699         && (texture->context == q || QGLContext::areSharing(q, texture->context)))
2700     {
2701         return texture;
2702     }
2703     return 0;
2704 }
2705 
2706 /*! \internal */
bindTexture(const QPixmap & pixmap,GLenum target,GLint format,QGLContext::BindOptions options)2707 QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options)
2708 {
2709     Q_Q(QGLContext);
2710     QPlatformPixmap *pd = pixmap.handle();
2711     Q_UNUSED(pd);
2712 
2713     const qint64 key = pixmap.cacheKey();
2714     QGLTexture *texture = textureCacheLookup(key, target);
2715     if (texture) {
2716         if (pixmap.paintingActive()) {
2717             // A QPainter is active on the pixmap - take the safe route and replace the texture.
2718             q->deleteTexture(texture->id);
2719             texture = 0;
2720         } else {
2721             qgl_functions()->glBindTexture(target, texture->id);
2722             return texture;
2723         }
2724     }
2725 
2726     if (!texture) {
2727         QImage image;
2728         QPaintEngine* paintEngine = pixmap.paintEngine();
2729         if (!paintEngine || paintEngine->type() != QPaintEngine::Raster)
2730             image = pixmap.toImage();
2731         else {
2732             // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it.
2733             // For performance reasons, we don't want that here, so we temporarily redirect the paint engine.
2734             QPaintDevice* currentPaintDevice = paintEngine->paintDevice();
2735             paintEngine->setPaintDevice(0);
2736             image = pixmap.toImage();
2737             paintEngine->setPaintDevice(currentPaintDevice);
2738         }
2739 
2740         // If the system depth is 16 and the pixmap doesn't have an alpha channel
2741         // then we convert it to RGB16 in the hope that it gets uploaded as a 16
2742         // bit texture which is much faster to access than a 32-bit one.
2743         if (pixmap.depth() == 16 && !image.hasAlphaChannel() )
2744             image = image.convertToFormat(QImage::Format_RGB16);
2745         texture = bindTexture(image, target, format, key, options);
2746     }
2747     // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
2748     Q_ASSERT(texture);
2749 
2750     if (texture->id > 0)
2751         QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
2752 
2753     return texture;
2754 }
2755 
2756 /*! \internal */
maxTextureSize()2757 int QGLContextPrivate::maxTextureSize()
2758 {
2759     if (max_texture_size != -1)
2760         return max_texture_size;
2761 
2762     QOpenGLFunctions *funcs = qgl_functions();
2763     funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
2764 
2765 #ifndef QT_OPENGL_ES
2766     Q_Q(QGLContext);
2767     if (!q->contextHandle()->isOpenGLES()) {
2768         GLenum proxy = GL_PROXY_TEXTURE_2D;
2769 
2770         GLint size;
2771         GLint next = 64;
2772         funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
2773         QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
2774         gl1funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
2775         if (size == 0) {
2776             return max_texture_size;
2777         }
2778         do {
2779             size = next;
2780             next = size * 2;
2781 
2782             if (next > max_texture_size)
2783                 break;
2784             funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
2785             gl1funcs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
2786         } while (next > size);
2787 
2788         max_texture_size = size;
2789     }
2790 #endif
2791 
2792     return max_texture_size;
2793 }
2794 
2795 /*!
2796   Returns a QGLFunctions object that is initialized for this context.
2797  */
functions() const2798 QGLFunctions *QGLContext::functions() const
2799 {
2800     QGLContextPrivate *d = const_cast<QGLContextPrivate *>(d_func());
2801     if (!d->functions) {
2802         d->functions = new QGLFunctions(this);
2803         d->functions->initializeGLFunctions(this);
2804     }
2805     return d->functions;
2806 }
2807 
2808 /*!
2809   Generates and binds a 2D GL texture to the current context, based
2810   on \a image. The generated texture id is returned and can be used in
2811   later \c glBindTexture() calls.
2812 
2813   \overload
2814 */
bindTexture(const QImage & image,GLenum target,GLint format)2815 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
2816 {
2817     if (image.isNull())
2818         return 0;
2819 
2820     Q_D(QGLContext);
2821     QGLTexture *texture = d->bindTexture(image, target, format, DefaultBindOption);
2822     return texture->id;
2823 }
2824 
2825 /*!
2826     \since 4.6
2827 
2828     Generates and binds a 2D GL texture to the current context, based
2829     on \a image. The generated texture id is returned and can be used
2830     in later \c glBindTexture() calls.
2831 
2832     The \a target parameter specifies the texture target. The default
2833     target is \c GL_TEXTURE_2D.
2834 
2835     The \a format parameter sets the internal format for the
2836     texture. The default format is \c GL_RGBA.
2837 
2838     The binding \a options are a set of options used to decide how to
2839     bind the texture to the context.
2840 
2841     The texture that is generated is cached, so multiple calls to
2842     bindTexture() with the same QImage will return the same texture
2843     id.
2844 
2845     Note that we assume default values for the glPixelStore() and
2846     glPixelTransfer() parameters.
2847 
2848     \sa deleteTexture()
2849 */
bindTexture(const QImage & image,GLenum target,GLint format,BindOptions options)2850 GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
2851 {
2852     if (image.isNull())
2853         return 0;
2854 
2855     Q_D(QGLContext);
2856     QGLTexture *texture = d->bindTexture(image, target, format, options);
2857     return texture->id;
2858 }
2859 
2860 /*! \overload
2861 
2862     Generates and binds a 2D GL texture based on \a pixmap.
2863 */
bindTexture(const QPixmap & pixmap,GLenum target,GLint format)2864 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
2865 {
2866     if (pixmap.isNull())
2867         return 0;
2868 
2869     Q_D(QGLContext);
2870     QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption);
2871     return texture->id;
2872 }
2873 
2874 /*!
2875   \overload
2876   \since 4.6
2877 
2878   Generates and binds a 2D GL texture to the current context, based
2879   on \a pixmap.
2880 */
bindTexture(const QPixmap & pixmap,GLenum target,GLint format,BindOptions options)2881 GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options)
2882 {
2883     if (pixmap.isNull())
2884         return 0;
2885 
2886     Q_D(QGLContext);
2887     QGLTexture *texture = d->bindTexture(pixmap, target, format, options);
2888     return texture->id;
2889 }
2890 
2891 /*!
2892     Removes the texture identified by \a id from the texture cache,
2893     and calls glDeleteTextures() to delete the texture from the
2894     context.
2895 
2896     \sa bindTexture()
2897 */
deleteTexture(GLuint id)2898 void QGLContext::deleteTexture(GLuint id)
2899 {
2900     if (QGLTextureCache::instance()->remove(this, id))
2901         return;
2902     qgl_functions()->glDeleteTextures(1, &id);
2903 }
2904 
qt_add_rect_to_array(const QRectF & r,GLfloat * array)2905 void qt_add_rect_to_array(const QRectF &r, GLfloat *array)
2906 {
2907     qreal left = r.left();
2908     qreal right = r.right();
2909     qreal top = r.top();
2910     qreal bottom = r.bottom();
2911 
2912     array[0] = left;
2913     array[1] = top;
2914     array[2] = right;
2915     array[3] = top;
2916     array[4] = right;
2917     array[5] = bottom;
2918     array[6] = left;
2919     array[7] = bottom;
2920 }
2921 
qt_add_texcoords_to_array(qreal x1,qreal y1,qreal x2,qreal y2,GLfloat * array)2922 void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, GLfloat *array)
2923 {
2924     array[0] = x1;
2925     array[1] = y1;
2926     array[2] = x2;
2927     array[3] = y1;
2928     array[4] = x2;
2929     array[5] = y2;
2930     array[6] = x1;
2931     array[7] = y2;
2932 }
2933 
2934 #if !defined(QT_OPENGL_ES_2)
2935 
qDrawTextureRect(const QRectF & target,GLint textureWidth,GLint textureHeight,GLenum textureTarget)2936 static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
2937 {
2938     QOpenGLFunctions *funcs = qgl_functions();
2939     GLfloat tx = 1.0f;
2940     GLfloat ty = 1.0f;
2941 
2942 #ifdef QT_OPENGL_ES
2943     Q_UNUSED(textureWidth);
2944     Q_UNUSED(textureHeight);
2945     Q_UNUSED(textureTarget);
2946 #else
2947     if (textureTarget != GL_TEXTURE_2D && !QOpenGLContext::currentContext()->isOpenGLES()) {
2948         if (textureWidth == -1 || textureHeight == -1) {
2949             QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
2950             gl1funcs->glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
2951             gl1funcs->glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
2952         }
2953 
2954         tx = GLfloat(textureWidth);
2955         ty = GLfloat(textureHeight);
2956     }
2957 #endif
2958 
2959     GLfloat texCoordArray[4*2] = {
2960         0, ty, tx, ty, tx, 0, 0, 0
2961     };
2962 
2963     GLfloat vertexArray[4*2];
2964     qt_add_rect_to_array(target, vertexArray);
2965 
2966     QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
2967     gl1funcs->glVertexPointer(2, GL_FLOAT, 0, vertexArray);
2968     gl1funcs->glTexCoordPointer(2, GL_FLOAT, 0, texCoordArray);
2969 
2970     gl1funcs->glEnableClientState(GL_VERTEX_ARRAY);
2971     gl1funcs->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2972     funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
2973 
2974     gl1funcs->glDisableClientState(GL_VERTEX_ARRAY);
2975     gl1funcs->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2976 }
2977 
2978 #endif // !QT_OPENGL_ES_2
2979 
2980 /*!
2981     \since 4.4
2982 
2983     This function supports the following use cases:
2984 
2985     \list
2986     \li On OpenGL and OpenGL ES 1.x it draws the given texture, \a textureId,
2987     to the given target rectangle, \a target, in OpenGL model space. The
2988     \a textureTarget should be a 2D texture target.
2989     \li On OpenGL and OpenGL ES 2.x, if a painter is active, not inside a
2990     beginNativePainting / endNativePainting block, and uses the
2991     engine with type QPaintEngine::OpenGL2, the function will draw the given
2992     texture, \a textureId, to the given target rectangle, \a target,
2993     respecting the current painter state. This will let you draw a texture
2994     with the clip, transform, render hints, and composition mode set by the
2995     painter. Note that the texture target needs to be GL_TEXTURE_2D for this
2996     use case, and that this is the only supported use case under OpenGL ES 2.x.
2997     \endlist
2998 
2999 */
drawTexture(const QRectF & target,GLuint textureId,GLenum textureTarget)3000 void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
3001 {
3002 #if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2)
3003      if (d_ptr->active_engine &&
3004          d_ptr->active_engine->type() == QPaintEngine::OpenGL2) {
3005          QGL2PaintEngineEx *eng = static_cast<QGL2PaintEngineEx*>(d_ptr->active_engine);
3006          if (!eng->isNativePaintingActive()) {
3007             QRectF src(0, 0, target.width(), target.height());
3008             QSize size(target.width(), target.height());
3009             if (eng->drawTexture(target, textureId, size, src))
3010                 return;
3011         }
3012      }
3013 #endif
3014 
3015 #ifndef QT_OPENGL_ES_2
3016      QOpenGLFunctions *funcs = qgl_functions();
3017      if (!contextHandle()->isOpenGLES()) {
3018 #ifdef QT_OPENGL_ES
3019         if (textureTarget != GL_TEXTURE_2D) {
3020             qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES");
3021             return;
3022         }
3023 #else
3024         const bool wasEnabled = funcs->glIsEnabled(GL_TEXTURE_2D);
3025         GLint oldTexture;
3026         funcs->glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
3027 #endif
3028 
3029         funcs->glEnable(textureTarget);
3030         funcs->glBindTexture(textureTarget, textureId);
3031 
3032         qDrawTextureRect(target, -1, -1, textureTarget);
3033 
3034 #ifdef QT_OPENGL_ES
3035         funcs->glDisable(textureTarget);
3036 #else
3037         if (!wasEnabled)
3038             funcs->glDisable(textureTarget);
3039         funcs->glBindTexture(textureTarget, oldTexture);
3040 #endif
3041         return;
3042     }
3043 #else
3044     Q_UNUSED(target);
3045     Q_UNUSED(textureId);
3046     Q_UNUSED(textureTarget);
3047 #endif
3048     qWarning("drawTexture() with OpenGL ES 2.0 requires an active OpenGL2 paint engine");
3049 }
3050 
3051 /*!
3052     \since 4.4
3053 
3054     This function supports the following use cases:
3055 
3056     \list
3057     \li By default it draws the given texture, \a textureId,
3058     at the given \a point in OpenGL model space. The
3059     \a textureTarget should be a 2D texture target.
3060     \li If a painter is active, not inside a
3061     beginNativePainting / endNativePainting block, and uses the
3062     engine with type QPaintEngine::OpenGL2, the function will draw the given
3063     texture, \a textureId, at the given \a point,
3064     respecting the current painter state. This will let you draw a texture
3065     with the clip, transform, render hints, and composition mode set by the
3066     painter. Note that the texture target needs to be GL_TEXTURE_2D for this
3067     use case.
3068     \endlist
3069 
3070     \note This function is not supported under any version of OpenGL ES.
3071 */
drawTexture(const QPointF & point,GLuint textureId,GLenum textureTarget)3072 void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
3073 {
3074 #ifdef QT_OPENGL_ES
3075     Q_UNUSED(point);
3076     Q_UNUSED(textureId);
3077     Q_UNUSED(textureTarget);
3078 #else
3079     if (!contextHandle()->isOpenGLES()) {
3080         QOpenGLFunctions *funcs = qgl_functions();
3081         const bool wasEnabled = funcs->glIsEnabled(GL_TEXTURE_2D);
3082         GLint oldTexture;
3083         funcs->glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexture);
3084 
3085         funcs->glEnable(textureTarget);
3086         funcs->glBindTexture(textureTarget, textureId);
3087 
3088         GLint textureWidth;
3089         GLint textureHeight;
3090 
3091         QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
3092         gl1funcs->glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_WIDTH, &textureWidth);
3093         gl1funcs->glGetTexLevelParameteriv(textureTarget, 0, GL_TEXTURE_HEIGHT, &textureHeight);
3094 
3095         if (d_ptr->active_engine &&
3096             d_ptr->active_engine->type() == QPaintEngine::OpenGL2) {
3097             QGL2PaintEngineEx *eng = static_cast<QGL2PaintEngineEx*>(d_ptr->active_engine);
3098             if (!eng->isNativePaintingActive()) {
3099                 QRectF dest(point, QSizeF(textureWidth, textureHeight));
3100                 QRectF src(0, 0, textureWidth, textureHeight);
3101                 QSize size(textureWidth, textureHeight);
3102                 if (eng->drawTexture(dest, textureId, size, src))
3103                     return;
3104             }
3105         }
3106 
3107         qDrawTextureRect(QRectF(point, QSizeF(textureWidth, textureHeight)), textureWidth, textureHeight, textureTarget);
3108 
3109         if (!wasEnabled)
3110             funcs->glDisable(textureTarget);
3111         funcs->glBindTexture(textureTarget, oldTexture);
3112         return;
3113     }
3114 #endif
3115     qWarning("drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES, use rect version instead");
3116 }
3117 
3118 /*!
3119     This function sets the limit for the texture cache to \a size,
3120     expressed in kilobytes.
3121 
3122     By default, the cache limit is approximately 64 MB.
3123 
3124     \sa textureCacheLimit()
3125 */
setTextureCacheLimit(int size)3126 void QGLContext::setTextureCacheLimit(int size)
3127 {
3128     QGLTextureCache::instance()->setMaxCost(size);
3129 }
3130 
3131 /*!
3132     Returns the current texture cache limit in kilobytes.
3133 
3134     \sa setTextureCacheLimit()
3135 */
textureCacheLimit()3136 int QGLContext::textureCacheLimit()
3137 {
3138     return QGLTextureCache::instance()->maxCost();
3139 }
3140 
3141 
3142 /*!
3143     \fn QGLFormat QGLContext::format() const
3144 
3145     Returns the frame buffer format that was obtained (this may be a
3146     subset of what was requested).
3147 
3148     \sa requestedFormat()
3149 */
3150 
3151 /*!
3152     \fn QGLFormat QGLContext::requestedFormat() const
3153 
3154     Returns the frame buffer format that was originally requested in
3155     the constructor or setFormat().
3156 
3157     \sa format()
3158 */
3159 
3160 /*!
3161     Sets a \a format for this context. The context is \l{reset()}{reset}.
3162 
3163     Call create() to create a new GL context that tries to match the
3164     new format.
3165 
3166     \snippet code/src_opengl_qgl.cpp 7
3167 
3168     \sa format(), reset(), create()
3169 */
3170 
setFormat(const QGLFormat & format)3171 void QGLContext::setFormat(const QGLFormat &format)
3172 {
3173     Q_D(QGLContext);
3174     reset();
3175     d->glFormat = d->reqFormat = format;
3176 }
3177 
3178 /*!
3179     \internal
3180 */
setDevice(QPaintDevice * pDev)3181 void QGLContext::setDevice(QPaintDevice *pDev)
3182 {
3183     Q_D(QGLContext);
3184     // Do not touch the valid flag here. The context is either a new one and
3185     // valid is not yet set or it is adapted from a valid QOpenGLContext in which
3186     // case it must remain valid.
3187     d->paintDevice = pDev;
3188     if (d->paintDevice && (d->paintDevice->devType() != QInternal::Widget
3189                            && d->paintDevice->devType() != QInternal::Pixmap
3190                            && d->paintDevice->devType() != QInternal::Pbuffer)) {
3191         qWarning("QGLContext: Unsupported paint device type");
3192     }
3193 }
3194 
3195 /*!
3196     \fn bool QGLContext::isValid() const
3197 
3198     Returns \c true if a GL rendering context has been successfully
3199     created; otherwise returns \c false.
3200 */
3201 
3202 /*!
3203     \fn void QGLContext::setValid(bool valid)
3204     \internal
3205 
3206     Forces the GL rendering context to be valid.
3207 */
3208 
3209 /*!
3210     \fn bool QGLContext::isSharing() const
3211 
3212     Returns \c true if this context is sharing its GL context with
3213     another QGLContext, otherwise false is returned. Note that context
3214     sharing might not be supported between contexts with different
3215     formats.
3216 */
3217 
3218 /*!
3219     Returns \c true if \a context1 and \a context2 are sharing their
3220     GL resources such as textures, shader programs, etc;
3221     otherwise returns \c false.
3222 
3223     \since 4.6
3224 */
areSharing(const QGLContext * context1,const QGLContext * context2)3225 bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2)
3226 {
3227     if (!context1 || !context2)
3228         return false;
3229     return context1->d_ptr->group == context2->d_ptr->group;
3230 }
3231 
3232 /*!
3233     \fn bool QGLContext::deviceIsPixmap() const
3234 
3235     Returns \c true if the paint device of this context is a pixmap;
3236     otherwise returns \c false.
3237 
3238     Since Qt 5 the paint device is never actually a pixmap. renderPixmap() is
3239     however still simulated using framebuffer objects and readbacks, and this
3240     function will return \c true in this case.
3241 */
3242 
3243 /*!
3244     \fn bool QGLContext::windowCreated() const
3245 
3246     Returns \c true if a window has been created for this context;
3247     otherwise returns \c false.
3248 
3249     \sa setWindowCreated()
3250 */
3251 
3252 /*!
3253     \fn void QGLContext::setWindowCreated(bool on)
3254 
3255     If \a on is true the context has had a window created for it. If
3256     \a on is false no window has been created for the context.
3257 
3258     \sa windowCreated()
3259 */
3260 
3261 /*!
3262     \fn uint QGLContext::colorIndex(const QColor& c) const
3263 
3264     \internal
3265 
3266     Returns a colormap index for the color c, in ColorIndex mode. Used
3267     by qglColor() and qglClearColor().
3268 */
colorIndex(const QColor &) const3269 uint QGLContext::colorIndex(const QColor&) const
3270 {
3271     return 0;
3272 }
3273 
3274 /*!
3275     \fn bool QGLContext::initialized() const
3276 
3277     Returns \c true if this context has been initialized, i.e. if
3278     QGLWidget::initializeGL() has been performed on it; otherwise
3279     returns \c false.
3280 
3281     \sa setInitialized()
3282 */
3283 
3284 /*!
3285     \fn void QGLContext::setInitialized(bool on)
3286 
3287     If \a on is true the context has been initialized, i.e.
3288     QGLContext::setInitialized() has been called on it. If \a on is
3289     false the context has not been initialized.
3290 
3291     \sa initialized()
3292 */
3293 
3294 /*!
3295     \fn const QGLContext* QGLContext::currentContext()
3296 
3297     Returns the current context, i.e. the context to which any OpenGL
3298     commands will currently be directed. Returns 0 if no context is
3299     current.
3300 
3301     \sa makeCurrent()
3302 */
3303 
3304 /*!
3305     \fn QColor QGLContext::overlayTransparentColor() const
3306 
3307     If this context is a valid context in an overlay plane, returns
3308     the plane's transparent color. Otherwise returns an \l{QColor::isValid()}{invalid} color.
3309 
3310     The returned color's \l{QColormap::pixel()}{pixel} value is
3311     the index of the transparent color in the colormap of the overlay
3312     plane. (Naturally, the color's RGB values are meaningless.)
3313 
3314     The returned QColor object will generally work as expected only
3315     when passed as the argument to QGLWidget::qglColor() or
3316     QGLWidget::qglClearColor(). Under certain circumstances it can
3317     also be used to draw transparent graphics with a QPainter.
3318 */
overlayTransparentColor() const3319 QColor QGLContext::overlayTransparentColor() const
3320 {
3321     return QColor(); // Invalid color
3322 }
3323 
3324 /*!
3325     Creates the GL context. Returns \c true if it was successful in
3326     creating a valid GL rendering context on the paint device
3327     specified in the constructor; otherwise returns \c false (i.e. the
3328     context is invalid).
3329 
3330     If the OpenGL implementation on your system does not support the requested
3331     version of OpenGL context, then QGLContext will try to create the closest
3332     matching version. The actual created context properties can be queried
3333     using the QGLFormat returned by the format() function. For example, if
3334     you request a context that supports OpenGL 4.3 Core profile but the driver
3335     and/or hardware only supports version 3.2 Core profile contexts then you will
3336     get a 3.2 Core profile context.
3337 
3338     After successful creation, format() returns the set of features of
3339     the created GL rendering context.
3340 
3341     If \a shareContext points to a valid QGLContext, this method will
3342     try to establish OpenGL display list and texture object sharing
3343     between this context and the \a shareContext. Note that this may
3344     fail if the two contexts have different \l {format()} {formats}.
3345     Use isSharing() to see if sharing is in effect.
3346 
3347     \warning Implementation note: initialization of C++ class
3348     members usually takes place in the class constructor. QGLContext
3349     is an exception because it must be simple to customize. The
3350     virtual functions chooseContext() (and chooseVisual() for X11) can
3351     be reimplemented in a subclass to select a particular context. The
3352     problem is that virtual functions are not properly called during
3353     construction (even though this is correct C++) because C++
3354     constructs class hierarchies from the bottom up. For this reason
3355     we need a create() function.
3356 
3357     \sa chooseContext(), format(), isValid()
3358 */
3359 
create(const QGLContext * shareContext)3360 bool QGLContext::create(const QGLContext* shareContext)
3361 {
3362     Q_D(QGLContext);
3363     if (!d->paintDevice && !d->guiGlContext)
3364         return false;
3365 
3366     reset();
3367     d->valid = chooseContext(shareContext);
3368     if (d->valid && d->paintDevice && d->paintDevice->devType() == QInternal::Widget) {
3369         QWidgetPrivate *wd = qt_widget_private(static_cast<QWidget *>(d->paintDevice));
3370         wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer();
3371     }
3372     return d->valid;
3373 }
3374 
isValid() const3375 bool QGLContext::isValid() const
3376 {
3377     Q_D(const QGLContext);
3378     return d->valid;
3379 }
3380 
setValid(bool valid)3381 void QGLContext::setValid(bool valid)
3382 {
3383     Q_D(QGLContext);
3384     d->valid = valid;
3385 }
3386 
isSharing() const3387 bool QGLContext::isSharing() const
3388 {
3389     Q_D(const QGLContext);
3390     return d->group->isSharing();
3391 }
3392 
format() const3393 QGLFormat QGLContext::format() const
3394 {
3395     Q_D(const QGLContext);
3396     return d->glFormat;
3397 }
3398 
requestedFormat() const3399 QGLFormat QGLContext::requestedFormat() const
3400 {
3401     Q_D(const QGLContext);
3402     return d->reqFormat;
3403 }
3404 
device() const3405  QPaintDevice* QGLContext::device() const
3406 {
3407     Q_D(const QGLContext);
3408     return d->paintDevice;
3409 }
3410 
deviceIsPixmap() const3411 bool QGLContext::deviceIsPixmap() const
3412 {
3413     Q_D(const QGLContext);
3414     return !d->readback_target_size.isEmpty();
3415 }
3416 
3417 
windowCreated() const3418 bool QGLContext::windowCreated() const
3419 {
3420     Q_D(const QGLContext);
3421     return d->crWin;
3422 }
3423 
3424 
setWindowCreated(bool on)3425 void QGLContext::setWindowCreated(bool on)
3426 {
3427     Q_D(QGLContext);
3428     d->crWin = on;
3429 }
3430 
initialized() const3431 bool QGLContext::initialized() const
3432 {
3433     Q_D(const QGLContext);
3434     return d->initDone;
3435 }
3436 
setInitialized(bool on)3437 void QGLContext::setInitialized(bool on)
3438 {
3439     Q_D(QGLContext);
3440     d->initDone = on;
3441 }
3442 
currentContext()3443 const QGLContext* QGLContext::currentContext()
3444 {
3445     if (const QOpenGLContext *threadContext = QOpenGLContext::currentContext()) {
3446         return QGLContext::fromOpenGLContext(const_cast<QOpenGLContext *>(threadContext));
3447     }
3448     return 0;
3449 }
3450 
setCurrentContext(QGLContext * context)3451 void QGLContextPrivate::setCurrentContext(QGLContext *context)
3452 {
3453     Q_UNUSED(context);
3454 }
3455 
3456 /*!
3457     Moves the QGLContext to the given \a thread.
3458 
3459     Enables calling swapBuffers() and makeCurrent() on the context in
3460     the given thread.
3461 */
moveToThread(QThread * thread)3462 void QGLContext::moveToThread(QThread *thread)
3463 {
3464     Q_D(QGLContext);
3465     if (d->guiGlContext)
3466         d->guiGlContext->moveToThread(thread);
3467 }
3468 
3469 /*!
3470     \fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
3471 
3472     This semi-internal function is called by create(). It creates a
3473     system-dependent OpenGL handle that matches the format() of \a
3474     shareContext as closely as possible, returning true if successful
3475     or false if a suitable handle could not be found.
3476 
3477     On Windows, it calls the virtual function choosePixelFormat(),
3478     which finds a matching pixel format identifier. On X11, it calls
3479     the virtual function chooseVisual() which finds an appropriate X
3480     visual. On other platforms it may work differently.
3481 */
chooseContext(const QGLContext * shareContext)3482 bool QGLContext::chooseContext(const QGLContext* shareContext)
3483 {
3484     Q_D(QGLContext);
3485     if(!d->paintDevice || d->paintDevice->devType() != QInternal::Widget) {
3486         // Unlike in Qt 4, the only possible target is a widget backed by an OpenGL-based
3487         // QWindow. Pixmaps in particular are not supported anymore as paint devices since
3488         // starting from Qt 5 QPixmap is raster-backed on almost all platforms.
3489         d->valid = false;
3490     }else {
3491         QWidget *widget = static_cast<QWidget *>(d->paintDevice);
3492         QGLFormat glformat = format();
3493         QSurfaceFormat winFormat = QGLFormat::toSurfaceFormat(glformat);
3494         if (widget->testAttribute(Qt::WA_TranslucentBackground))
3495             winFormat.setAlphaBufferSize(qMax(winFormat.alphaBufferSize(), 8));
3496 
3497         QWindow *window = widget->windowHandle();
3498         if (!window->handle()
3499             || window->surfaceType() != QWindow::OpenGLSurface
3500             || window->requestedFormat() != winFormat)
3501         {
3502             window->setSurfaceType(QWindow::OpenGLSurface);
3503             window->setFormat(winFormat);
3504             window->destroy();
3505             window->create();
3506         }
3507 
3508         if (d->ownContext)
3509             delete d->guiGlContext;
3510         d->ownContext = true;
3511         QOpenGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0;
3512         d->guiGlContext = new QOpenGLContext;
3513         d->guiGlContext->setFormat(winFormat);
3514         d->guiGlContext->setShareContext(shareGlContext);
3515         d->valid = d->guiGlContext->create();
3516 
3517         if (d->valid)
3518             d->guiGlContext->setQGLContextHandle(this, 0);
3519 
3520         d->glFormat = QGLFormat::fromSurfaceFormat(d->guiGlContext->format());
3521         d->setupSharing();
3522     }
3523 
3524 
3525     return d->valid;
3526 }
3527 
3528 /*!
3529     \fn void QGLContext::reset()
3530 
3531     Resets the context and makes it invalid.
3532 
3533     \sa create(), isValid()
3534 */
reset()3535 void QGLContext::reset()
3536 {
3537     Q_D(QGLContext);
3538     if (!d->valid)
3539         return;
3540     d->cleanup();
3541 
3542     d->crWin = false;
3543     d->sharing = false;
3544     d->valid = false;
3545     d->transpColor = QColor();
3546     d->initDone = false;
3547     QGLContextGroup::removeShare(this);
3548     if (d->guiGlContext) {
3549         if (QOpenGLContext::currentContext() == d->guiGlContext)
3550             doneCurrent();
3551         if (d->ownContext) {
3552             if (d->guiGlContext->thread() == QThread::currentThread())
3553                 delete d->guiGlContext;
3554             else
3555                 d->guiGlContext->deleteLater();
3556         } else
3557             d->guiGlContext->setQGLContextHandle(0,0);
3558         d->guiGlContext = 0;
3559     }
3560     d->ownContext = false;
3561 }
3562 
3563 /*!
3564     \fn void QGLContext::makeCurrent()
3565 
3566     Makes this context the current OpenGL rendering context. All GL
3567     functions you call operate on this context until another context
3568     is made current.
3569 
3570     In some very rare cases the underlying call may fail. If this
3571     occurs an error message is output to stderr.
3572 
3573     If you call this from a thread other than the main UI thread,
3574     make sure you've first pushed the context to the relevant thread
3575     from the UI thread using moveToThread().
3576 */
makeCurrent()3577 void QGLContext::makeCurrent()
3578 {
3579     Q_D(QGLContext);
3580     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
3581         return;
3582 
3583     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
3584     if (!widget->windowHandle())
3585         return;
3586 
3587     if (d->guiGlContext->makeCurrent(widget->windowHandle())) {
3588         if (!d->workaroundsCached) {
3589             d->workaroundsCached = true;
3590             const char *renderer = reinterpret_cast<const char *>(d->guiGlContext->functions()->glGetString(GL_RENDERER));
3591             if (renderer && strstr(renderer, "Mali")) {
3592                 d->workaround_brokenFBOReadBack = true;
3593             }
3594         }
3595     }
3596 }
3597 
3598 /*!
3599     \fn void QGLContext::swapBuffers() const
3600 
3601     Call this to finish a frame of OpenGL rendering, and make sure to
3602     call makeCurrent() again before issuing any further OpenGL commands,
3603     for example as part of a new frame.
3604 */
swapBuffers() const3605 void QGLContext::swapBuffers() const
3606 {
3607     Q_D(const QGLContext);
3608     if (!d->paintDevice || d->paintDevice->devType() != QInternal::Widget)
3609         return;
3610 
3611     QWidget *widget = static_cast<QWidget *>(d->paintDevice);
3612     if (!widget->windowHandle())
3613         return;
3614 
3615     d->guiGlContext->swapBuffers(widget->windowHandle());
3616 }
3617 
3618 /*!
3619     \fn void QGLContext::doneCurrent()
3620 
3621     Makes no GL context the current context. Normally, you do not need
3622     to call this function; QGLContext calls it as necessary.
3623 */
doneCurrent()3624 void QGLContext::doneCurrent()
3625 {
3626     Q_D(QGLContext);
3627     d->guiGlContext->doneCurrent();
3628 }
3629 
3630 /*!
3631     \fn QPaintDevice* QGLContext::device() const
3632 
3633     Returns the paint device set for this context.
3634 
3635     \sa QGLContext::QGLContext()
3636 */
3637 
3638 /*****************************************************************************
3639   QGLWidget implementation
3640  *****************************************************************************/
3641 
3642 
3643 /*!
3644     \class QGLWidget
3645     \inmodule QtOpenGL
3646     \obsolete
3647 
3648     \brief The QGLWidget class is a widget for rendering OpenGL graphics.
3649 
3650     QGLWidget provides functionality for displaying OpenGL graphics
3651     integrated into a Qt application. It is very simple to use. You
3652     inherit from it and use the subclass like any other QWidget,
3653     except that you have the choice between using QPainter and
3654     standard OpenGL rendering commands.
3655 
3656     \note This class is part of the legacy \l {Qt OpenGL} module and,
3657     like the other \c QGL classes, should be avoided in the new
3658     applications. Instead, starting from Qt 5.4, prefer using
3659     QOpenGLWidget and the \c QOpenGL classes.
3660 
3661     QGLWidget provides three convenient virtual functions that you can
3662     reimplement in your subclass to perform the typical OpenGL tasks:
3663 
3664     \list
3665     \li paintGL() - Renders the OpenGL scene. Gets called whenever the widget
3666     needs to be updated.
3667     \li resizeGL() - Sets up the OpenGL viewport, projection, etc. Gets
3668     called whenever the widget has been resized (and also when it
3669     is shown for the first time because all newly created widgets get a
3670     resize event automatically).
3671     \li initializeGL() - Sets up the OpenGL rendering context, defines display
3672     lists, etc. Gets called once before the first time resizeGL() or
3673     paintGL() is called.
3674     \endlist
3675 
3676     Here is a rough outline of how a QGLWidget subclass might look:
3677 
3678     \snippet code/src_opengl_qgl.cpp 8
3679 
3680     If you need to trigger a repaint from places other than paintGL()
3681     (a typical example is when using \l{QTimer}{timers} to
3682     animate scenes), you should call the widget's updateGL() function.
3683 
3684     Your widget's OpenGL rendering context is made current when
3685     paintGL(), resizeGL(), or initializeGL() is called. If you need to
3686     call the standard OpenGL API functions from other places (e.g. in
3687     your widget's constructor or in your own paint functions), you
3688     must call makeCurrent() first.
3689 
3690     QGLWidget provides functions for requesting a new display
3691     \l{QGLFormat}{format} and you can also create widgets with
3692     customized rendering \l{QGLContext}{contexts}.
3693 
3694     You can also share OpenGL display lists between QGLWidget objects (see
3695     the documentation of the QGLWidget constructors for details).
3696 
3697     Note that under Windows, the QGLContext belonging to a QGLWidget
3698     has to be recreated when the QGLWidget is reparented. This is
3699     necessary due to limitations on the Windows platform. This will
3700     most likely cause problems for users that have subclassed and
3701     installed their own QGLContext on a QGLWidget. It is possible to
3702     work around this issue by putting the QGLWidget inside a dummy
3703     widget and then reparenting the dummy widget, instead of the
3704     QGLWidget. This will side-step the issue altogether, and is what
3705     we recommend for users that need this kind of functionality.
3706 
3707     On \macos, when Qt is built with Cocoa support, a QGLWidget
3708     can't have any sibling widgets placed ontop of itself. This is due
3709     to limitations in the Cocoa API and is not supported by Apple.
3710 
3711     \section1 Overlays
3712 
3713     The QGLWidget creates a GL overlay context in addition to the
3714     normal context if overlays are supported by the underlying system.
3715 
3716     If you want to use overlays, you specify it in the
3717     \l{QGLFormat}{format}. (Note: Overlay must be requested in the format
3718     passed to the QGLWidget constructor.) Your GL widget should also
3719     implement some or all of these virtual methods:
3720 
3721     \list
3722     \li paintOverlayGL()
3723     \li resizeOverlayGL()
3724     \li initializeOverlayGL()
3725     \endlist
3726 
3727     These methods work in the same way as the normal paintGL() etc.
3728     functions, except that they will be called when the overlay
3729     context is made current. You can explicitly make the overlay
3730     context current by using makeOverlayCurrent(), and you can access
3731     the overlay context directly (e.g. to ask for its transparent
3732     color) by calling overlayContext().
3733 
3734     On X servers in which the default visual is in an overlay plane,
3735     non-GL Qt windows can also be used for overlays.
3736 
3737     \section1 Painting Techniques
3738 
3739     As described above, subclass QGLWidget to render pure 3D content in the
3740     following way:
3741 
3742     \list
3743     \li Reimplement the QGLWidget::initializeGL() and QGLWidget::resizeGL() to
3744        set up the OpenGL state and provide a perspective transformation.
3745     \li Reimplement QGLWidget::paintGL() to paint the 3D scene, calling only
3746        OpenGL functions to draw on the widget.
3747     \endlist
3748 
3749     It is also possible to draw 2D graphics onto a QGLWidget subclass, it is necessary
3750     to reimplement QGLWidget::paintEvent() and do the following:
3751 
3752     \list
3753     \li Construct a QPainter object.
3754     \li Initialize it for use on the widget with the QPainter::begin() function.
3755     \li Draw primitives using QPainter's member functions.
3756     \li Call QPainter::end() to finish painting.
3757     \endlist
3758 
3759     \section1 Threading
3760 
3761     As of Qt version 4.8, support for doing threaded GL rendering has
3762     been improved. There are three scenarios that we currently support:
3763     \list
3764     \li 1. Buffer swapping in a thread.
3765 
3766     Swapping buffers in a double buffered context may be a
3767     synchronous, locking call that may be a costly operation in some
3768     GL implementations. Especially so on embedded devices. It's not
3769     optimal to have the CPU idling while the GPU is doing a buffer
3770     swap. In those cases it is possible to do the rendering in the
3771     main thread and do the actual buffer swap in a separate
3772     thread. This can be done with the following steps:
3773 
3774     1. Call doneCurrent() in the main thread when the rendering is
3775     finished.
3776 
3777     2. Call QGLContext::moveToThread(swapThread) to transfer ownership
3778     of the context to the swapping thread.
3779 
3780     3. Notify the swapping thread that it can grab the context.
3781 
3782     4. Make the rendering context current in the swapping thread with
3783     makeCurrent() and then call swapBuffers().
3784 
3785     5. Call doneCurrent() in the swapping thread.
3786 
3787     6. Call QGLContext::moveToThread(qApp->thread()) and notify the
3788     main thread that swapping is done.
3789 
3790     Doing this will free up the main thread so that it can continue
3791     with, for example, handling UI events or network requests. Even if
3792     there is a context swap involved, it may be preferable compared to
3793     having the main thread wait while the GPU finishes the swap
3794     operation. Note that this is highly implementation dependent.
3795 
3796     \li 2. Texture uploading in a thread.
3797 
3798     Doing texture uploads in a thread may be very useful for
3799     applications handling large amounts of images that needs to be
3800     displayed, like for instance a photo gallery application. This is
3801     supported in Qt through the existing bindTexture() API. A simple
3802     way of doing this is to create two sharing QGLWidgets. One is made
3803     current in the main GUI thread, while the other is made current in
3804     the texture upload thread. The widget in the uploading thread is
3805     never shown, it is only used for sharing textures with the main
3806     thread. For each texture that is bound via bindTexture(), notify
3807     the main thread so that it can start using the texture.
3808 
3809     \li 3. Using QPainter to draw into a QGLWidget in a thread.
3810 
3811     In Qt 4.8, it is possible to draw into a QGLWidget using a
3812     QPainter in a separate thread. Note that this is also possible for
3813     QGLPixelBuffers and QGLFramebufferObjects. Since this is only
3814     supported in the GL 2 paint engine, OpenGL 2.0 or OpenGL ES 2.0 is
3815     required.
3816 
3817     QGLWidgets can only be created in the main GUI thread. This means
3818     a call to doneCurrent() is necessary to release the GL context
3819     from the main thread, before the widget can be drawn into by
3820     another thread. You then need to call QGLContext::moveToThread()
3821     to transfer ownership of the context to the thread in which you
3822     want to make it current.
3823     Also, the main GUI thread will dispatch resize and
3824     paint events to a QGLWidget when the widget is resized, or parts
3825     of it becomes exposed or needs redrawing. It is therefore
3826     necessary to handle those events because the default
3827     implementations inside QGLWidget will try to make the QGLWidget's
3828     context current, which again will interfere with any threads
3829     rendering into the widget. Reimplement QGLWidget::paintEvent() and
3830     QGLWidget::resizeEvent() to notify the rendering thread that a
3831     resize or update is necessary, and be careful not to call the base
3832     class implementation. If you are rendering an animation, it might
3833     not be necessary to handle the paint event at all since the
3834     rendering thread is doing regular updates. Then it would be enough
3835     to reimplement QGLWidget::paintEvent() to do nothing.
3836 
3837     \endlist
3838 
3839     As a general rule when doing threaded rendering: be aware that
3840     binding and releasing contexts in different threads have to be
3841     synchronized by the user. A GL rendering context can only be
3842     current in one thread at any time. If you try to open a QPainter
3843     on a QGLWidget and the widget's rendering context is current in
3844     another thread, it will fail.
3845 
3846     In addition to this, rendering using raw GL calls in a separate
3847     thread is supported.
3848 
3849     \e{OpenGL is a trademark of Silicon Graphics, Inc. in the United States and other
3850     countries.}
3851 
3852     \sa QOpenGLWidget, QGLPixelBuffer
3853 */
3854 
3855 /*!
3856     Constructs an OpenGL widget with a \a parent widget.
3857 
3858     The \l{QGLFormat::defaultFormat()}{default format} is
3859     used. The widget will be \l{isValid()}{invalid} if the
3860     system has no \l{QGLFormat::hasOpenGL()}{OpenGL support}.
3861 
3862     The \a parent and widget flag, \a f, arguments are passed
3863     to the QWidget constructor.
3864 
3865     If \a shareWidget is a valid QGLWidget, this widget will share
3866     OpenGL display lists and texture objects with \a shareWidget. But
3867     if \a shareWidget and this widget have different \l {format()}
3868     {formats}, sharing might not be possible. You can check whether
3869     sharing is in effect by calling isSharing().
3870 
3871     The initialization of OpenGL rendering state, etc. should be done
3872     by overriding the initializeGL() function, rather than in the
3873     constructor of your QGLWidget subclass.
3874 
3875     \sa QGLFormat::defaultFormat(), {Textures Example}
3876 */
3877 
QGLWidget(QWidget * parent,const QGLWidget * shareWidget,Qt::WindowFlags f)3878 QGLWidget::QGLWidget(QWidget *parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
3879     : QWidget(*(new QGLWidgetPrivate), parent, f)
3880 {
3881     Q_D(QGLWidget);
3882     d->init(new QGLContext(QGLFormat::defaultFormat(), this), shareWidget);
3883 }
3884 
3885 /*!
3886   \internal
3887  */
QGLWidget(QGLWidgetPrivate & dd,const QGLFormat & format,QWidget * parent,const QGLWidget * shareWidget,Qt::WindowFlags f)3888 QGLWidget::QGLWidget(QGLWidgetPrivate &dd, const QGLFormat &format, QWidget *parent, const QGLWidget *shareWidget, Qt::WindowFlags f)
3889     : QWidget(dd, parent, f)
3890 {
3891     Q_D(QGLWidget);
3892     d->init(new QGLContext(format, this), shareWidget);
3893 
3894 }
3895 
3896 
3897 /*!
3898     Constructs an OpenGL widget with parent \a parent.
3899 
3900     The \a format argument specifies the desired
3901     \l{QGLFormat}{rendering options}.
3902     If the underlying OpenGL/Window system
3903     cannot satisfy all the features requested in \a format, the
3904     nearest subset of features will be used. After creation, the
3905     format() method will return the actual format obtained.
3906 
3907     The widget will be \l{isValid()}{invalid} if the system
3908     has no \l{QGLFormat::hasOpenGL()}{OpenGL support}.
3909 
3910     The \a parent and widget flag, \a f, arguments are passed
3911     to the QWidget constructor.
3912 
3913     If \a shareWidget is a valid QGLWidget, this widget will share
3914     OpenGL display lists and texture objects with \a shareWidget. But
3915     if \a shareWidget and this widget have different \l {format()}
3916     {formats}, sharing might not be possible. You can check whether
3917     sharing is in effect by calling isSharing().
3918 
3919     The initialization of OpenGL rendering state, etc. should be done
3920     by overriding the initializeGL() function, rather than in the
3921     constructor of your QGLWidget subclass.
3922 
3923     \sa QGLFormat::defaultFormat(), isValid()
3924 */
3925 
QGLWidget(const QGLFormat & format,QWidget * parent,const QGLWidget * shareWidget,Qt::WindowFlags f)3926 QGLWidget::QGLWidget(const QGLFormat &format, QWidget *parent, const QGLWidget* shareWidget,
3927                      Qt::WindowFlags f)
3928     : QWidget(*(new QGLWidgetPrivate), parent, f)
3929 {
3930     Q_D(QGLWidget);
3931     d->init(new QGLContext(format, this), shareWidget);
3932 }
3933 
3934 /*!
3935     Constructs an OpenGL widget with parent \a parent.
3936 
3937     The \a context argument is a pointer to the QGLContext that
3938     you wish to be bound to this widget. This allows you to pass in
3939     your own QGLContext sub-classes.
3940 
3941     The widget will be \l{isValid()}{invalid} if the system
3942     has no \l{QGLFormat::hasOpenGL()}{OpenGL support}.
3943 
3944     The \a parent and widget flag, \a f, arguments are passed
3945     to the QWidget constructor.
3946 
3947     If \a shareWidget is a valid QGLWidget, this widget will share
3948     OpenGL display lists and texture objects with \a shareWidget. But
3949     if \a shareWidget and this widget have different \l {format()}
3950     {formats}, sharing might not be possible. You can check whether
3951     sharing is in effect by calling isSharing().
3952 
3953     The initialization of OpenGL rendering state, etc. should be done
3954     by overriding the initializeGL() function, rather than in the
3955     constructor of your QGLWidget subclass.
3956 
3957     \sa QGLFormat::defaultFormat(), isValid()
3958 */
QGLWidget(QGLContext * context,QWidget * parent,const QGLWidget * shareWidget,Qt::WindowFlags f)3959 QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, const QGLWidget *shareWidget,
3960                      Qt::WindowFlags f)
3961     : QWidget(*(new QGLWidgetPrivate), parent, f)
3962 {
3963     Q_D(QGLWidget);
3964     d->init(context, shareWidget);
3965 }
3966 
3967 /*!
3968     Destroys the widget.
3969 */
3970 
~QGLWidget()3971 QGLWidget::~QGLWidget()
3972 {
3973     Q_D(QGLWidget);
3974     delete d->glcx;
3975     d->glcx = 0;
3976     d->cleanupColormaps();
3977 }
3978 
3979 /*!
3980     \fn QGLFormat QGLWidget::format() const
3981 
3982     Returns the format of the contained GL rendering context.
3983 */
3984 
3985 /*!
3986     \fn bool QGLWidget::doubleBuffer() const
3987 
3988     Returns \c true if the contained GL rendering context has double
3989     buffering; otherwise returns \c false.
3990 
3991     \sa QGLFormat::doubleBuffer()
3992 */
3993 
3994 /*!
3995     \fn void QGLWidget::setAutoBufferSwap(bool on)
3996 
3997     If \a on is true automatic GL buffer swapping is switched on;
3998     otherwise it is switched off.
3999 
4000     If \a on is true and the widget is using a double-buffered format,
4001     the background and foreground GL buffers will automatically be
4002     swapped after each paintGL() call.
4003 
4004     The buffer auto-swapping is on by default.
4005 
4006     \sa autoBufferSwap(), doubleBuffer(), swapBuffers()
4007 */
4008 
4009 /*!
4010     \fn bool QGLWidget::autoBufferSwap() const
4011 
4012     Returns \c true if the widget is doing automatic GL buffer swapping;
4013     otherwise returns \c false.
4014 
4015     \sa setAutoBufferSwap()
4016 */
4017 
4018 /*!
4019     \fn QFunctionPointer QGLContext::getProcAddress(const QString &proc) const
4020 
4021     Returns a function pointer to the GL extension function passed in
4022     \a proc. \nullptr is returned if a pointer to the function could not be
4023     obtained.
4024 */
getProcAddress(const QString & procName) const4025 QFunctionPointer QGLContext::getProcAddress(const QString &procName) const
4026 {
4027     Q_D(const QGLContext);
4028     return d->guiGlContext->getProcAddress(procName.toLatin1());
4029 }
4030 
4031 /*!
4032     \fn bool QGLWidget::isValid() const
4033 
4034     Returns \c true if the widget has a valid GL rendering context;
4035     otherwise returns \c false. A widget will be invalid if the system
4036     has no \l{QGLFormat::hasOpenGL()}{OpenGL support}.
4037 */
4038 
isValid() const4039 bool QGLWidget::isValid() const
4040 {
4041     Q_D(const QGLWidget);
4042     return d->glcx && d->glcx->isValid();
4043 }
4044 
4045 /*!
4046     \fn bool QGLWidget::isSharing() const
4047 
4048     Returns \c true if this widget's GL context is shared with another GL
4049     context, otherwise false is returned. Context sharing might not be
4050     possible if the widgets use different formats.
4051 
4052     \sa format()
4053 */
4054 
isSharing() const4055 bool QGLWidget::isSharing() const
4056 {
4057     Q_D(const QGLWidget);
4058     return d->glcx->isSharing();
4059 }
4060 
4061 /*!
4062     \fn void QGLWidget::makeCurrent()
4063 
4064     Makes this widget the current widget for OpenGL operations, i.e.
4065     makes the widget's rendering context the current OpenGL rendering
4066     context.
4067 */
4068 
makeCurrent()4069 void QGLWidget::makeCurrent()
4070 {
4071     Q_D(QGLWidget);
4072     d->makeCurrent();
4073 }
4074 
makeCurrent()4075 bool QGLWidgetPrivate::makeCurrent()
4076 {
4077     glcx->makeCurrent();
4078     return QGLContext::currentContext() == glcx;
4079 }
4080 
4081 /*!
4082     \fn void QGLWidget::doneCurrent()
4083 
4084     Makes no GL context the current context. Normally, you do not need
4085     to call this function; QGLContext calls it as necessary. However,
4086     it may be useful in multithreaded environments.
4087 */
4088 
doneCurrent()4089 void QGLWidget::doneCurrent()
4090 {
4091     Q_D(QGLWidget);
4092     d->glcx->doneCurrent();
4093 }
4094 
4095 /*!
4096     \fn void QGLWidget::swapBuffers()
4097 
4098     Swaps the screen contents with an off-screen buffer. This only
4099     works if the widget's format specifies double buffer mode.
4100 
4101     Normally, there is no need to explicitly call this function
4102     because it is done automatically after each widget repaint, i.e.
4103     each time after paintGL() has been executed.
4104 
4105     \sa doubleBuffer(), setAutoBufferSwap(), QGLFormat::setDoubleBuffer()
4106 */
4107 
swapBuffers()4108 void QGLWidget::swapBuffers()
4109 {
4110     Q_D(QGLWidget);
4111     d->glcx->swapBuffers();
4112 }
4113 
4114 
4115 /*!
4116     \fn const QGLContext* QGLWidget::overlayContext() const
4117 
4118     Returns the overlay context of this widget, or \nullptr if this
4119     widget has no overlay.
4120 
4121     \sa context()
4122 */
overlayContext() const4123 const QGLContext* QGLWidget::overlayContext() const
4124 {
4125     return nullptr;
4126 }
4127 
4128 /*!
4129     \fn void QGLWidget::makeOverlayCurrent()
4130 
4131     Makes the overlay context of this widget current. Use this if you
4132     need to issue OpenGL commands to the overlay context outside of
4133     initializeOverlayGL(), resizeOverlayGL(), and paintOverlayGL().
4134 
4135     Does nothing if this widget has no overlay.
4136 
4137     \sa makeCurrent()
4138 */
makeOverlayCurrent()4139 void QGLWidget::makeOverlayCurrent()
4140 {
4141 }
4142 
4143 /*!
4144   \obsolete
4145 
4146   Sets a new format for this widget.
4147 
4148   If the underlying OpenGL/Window system cannot satisfy all the
4149   features requested in \a format, the nearest subset of features will
4150   be used. After creation, the format() method will return the actual
4151   rendering context format obtained.
4152 
4153   The widget will be assigned a new QGLContext, and the initializeGL()
4154   function will be executed for this new context before the first
4155   resizeGL() or paintGL().
4156 
4157   This method will try to keep display list and texture object sharing
4158   in effect with other QGLWidget objects, but changing the format might make
4159   sharing impossible. Use isSharing() to see if sharing is still in
4160   effect.
4161 
4162   \sa format(), isSharing(), isValid()
4163 */
4164 
setFormat(const QGLFormat & format)4165 void QGLWidget::setFormat(const QGLFormat &format)
4166 {
4167     setContext(new QGLContext(format,this));
4168 }
4169 
4170 
4171 
4172 
4173 /*!
4174     \fn QGLContext *QGLWidget::context() const
4175 
4176     Returns the context of this widget.
4177 
4178     It is possible that the context is not valid (see isValid()), for
4179     example, if the underlying hardware does not support the format
4180     attributes that were requested.
4181 */
4182 
4183 /*!
4184   \fn void QGLWidget::setContext(QGLContext *context,
4185                                  const QGLContext* shareContext,
4186                                  bool deleteOldContext)
4187   \obsolete
4188 
4189   Sets a new context for this widget. The QGLContext \a context must
4190   be created using \e new. QGLWidget will delete \a context when
4191   another context is set or when the widget is destroyed.
4192 
4193   If \a context is invalid, QGLContext::create() is performed on
4194   it. The initializeGL() function will then be executed for the new
4195   context before the first resizeGL() or paintGL().
4196 
4197   If \a context is invalid, this method will try to keep display list
4198   and texture object sharing in effect, or (if \a shareContext points
4199   to a valid context) start display list and texture object sharing
4200   with that context, but sharing might be impossible if the two
4201   contexts have different \l {format()} {formats}. Use isSharing() to
4202   see whether sharing is in effect.
4203 
4204   If \a deleteOldContext is true (the default), the existing context
4205   will be deleted. You may use false here if you have kept a pointer
4206   to the old context (as returned by context()), and want to restore
4207   that context later.
4208 
4209   \note This function is obsolete and should no longer be used. If you were
4210   using it to recreate the context for a QGLWidget, you should instead create a
4211   new QGLWidget or use the QOpenGLContext API in conjunction with QWindow.
4212   There is currently no officially supported way to substitute QGLWidget's
4213   context with your own implementation of QGLContext.
4214 
4215   \sa context(), isSharing()
4216 */
setContext(QGLContext * context,const QGLContext * shareContext,bool deleteOldContext)4217 void QGLWidget::setContext(QGLContext *context,
4218                             const QGLContext* shareContext,
4219                             bool deleteOldContext)
4220 {
4221     Q_D(QGLWidget);
4222     if (context == 0) {
4223         qWarning("QGLWidget::setContext: Cannot set null context");
4224         return;
4225     }
4226 
4227     if (context->device() == 0) // a context may refere to more than 1 window.
4228         context->setDevice(this); //but its better to point to 1 of them than none of them.
4229 
4230     QGLContext* oldcx = d->glcx;
4231     d->glcx = context;
4232 
4233     if (!d->glcx->isValid())
4234         d->glcx->create(shareContext ? shareContext : oldcx);
4235 
4236     if (deleteOldContext)
4237         delete oldcx;
4238 }
4239 
4240 /*!
4241     \fn void QGLWidget::updateGL()
4242 
4243     Updates the widget by calling glDraw().
4244 */
4245 
updateGL()4246 void QGLWidget::updateGL()
4247 {
4248     Q_D(QGLWidget);
4249     const bool targetIsOffscreen = !d->glcx->d_ptr->readback_target_size.isEmpty();
4250     if (updatesEnabled() && (testAttribute(Qt::WA_Mapped) || targetIsOffscreen))
4251         glDraw();
4252 }
4253 
4254 
4255 /*!
4256     \fn void QGLWidget::updateOverlayGL()
4257 
4258     Updates the widget's overlay (if any). Will cause the virtual
4259     function paintOverlayGL() to be executed.
4260 
4261     The widget's rendering context will become the current context and
4262     initializeGL() will be called if it hasn't already been called.
4263 */
updateOverlayGL()4264 void QGLWidget::updateOverlayGL()
4265 {
4266 }
4267 
4268 /*!
4269     This virtual function is called once before the first call to
4270     paintGL() or resizeGL(), and then once whenever the widget has
4271     been assigned a new QGLContext. Reimplement it in a subclass.
4272 
4273     This function should set up any required OpenGL context rendering
4274     flags, defining display lists, etc.
4275 
4276     There is no need to call makeCurrent() because this has already
4277     been done when this function is called.
4278 */
4279 
initializeGL()4280 void QGLWidget::initializeGL()
4281 {
4282 }
4283 
4284 
4285 /*!
4286     This virtual function is called whenever the widget needs to be
4287     painted. Reimplement it in a subclass.
4288 
4289     There is no need to call makeCurrent() because this has already
4290     been done when this function is called.
4291 */
4292 
paintGL()4293 void QGLWidget::paintGL()
4294 {
4295     qgl_functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4296 }
4297 
4298 
4299 /*!
4300     \fn void QGLWidget::resizeGL(int width , int height)
4301 
4302     This virtual function is called whenever the widget has been
4303     resized. The new size is passed in \a width and \a height.
4304     Reimplement it in a subclass.
4305 
4306     There is no need to call makeCurrent() because this has already
4307     been done when this function is called.
4308 */
4309 
resizeGL(int,int)4310 void QGLWidget::resizeGL(int, int)
4311 {
4312 }
4313 
4314 
4315 
4316 /*!
4317     This virtual function is used in the same manner as initializeGL()
4318     except that it operates on the widget's overlay context instead of
4319     the widget's main context. This means that initializeOverlayGL()
4320     is called once before the first call to paintOverlayGL() or
4321     resizeOverlayGL(). Reimplement it in a subclass.
4322 
4323     This function should set up any required OpenGL context rendering
4324     flags, defining display lists, etc. for the overlay context.
4325 
4326     There is no need to call makeOverlayCurrent() because this has
4327     already been done when this function is called.
4328 */
4329 
initializeOverlayGL()4330 void QGLWidget::initializeOverlayGL()
4331 {
4332 }
4333 
4334 
4335 /*!
4336     This virtual function is used in the same manner as paintGL()
4337     except that it operates on the widget's overlay context instead of
4338     the widget's main context. This means that paintOverlayGL() is
4339     called whenever the widget's overlay needs to be painted.
4340     Reimplement it in a subclass.
4341 
4342     There is no need to call makeOverlayCurrent() because this has
4343     already been done when this function is called.
4344 */
4345 
paintOverlayGL()4346 void QGLWidget::paintOverlayGL()
4347 {
4348 }
4349 
4350 
4351 /*!
4352     \fn void QGLWidget::resizeOverlayGL(int width , int height)
4353 
4354     This virtual function is used in the same manner as paintGL()
4355     except that it operates on the widget's overlay context instead of
4356     the widget's main context. This means that resizeOverlayGL() is
4357     called whenever the widget has been resized. The new size is
4358     passed in \a width and \a height. Reimplement it in a subclass.
4359 
4360     There is no need to call makeOverlayCurrent() because this has
4361     already been done when this function is called.
4362 */
4363 
resizeOverlayGL(int,int)4364 void QGLWidget::resizeOverlayGL(int, int)
4365 {
4366 }
4367 
4368 /*!\reimp
4369 */
event(QEvent * e)4370 bool QGLWidget::event(QEvent *e)
4371 {
4372     Q_D(QGLWidget);
4373 
4374     // A re-parent will destroy the window and re-create it. We should not reset the context while it happens.
4375     if (e->type() == QEvent::ParentAboutToChange)
4376         d->parent_changing = true;
4377 
4378     if (e->type() == QEvent::ParentChange)
4379         d->parent_changing = false;
4380 
4381     return QWidget::event(e);
4382 }
4383 
4384 /*!
4385     \fn void QGLWidget::paintEvent(QPaintEvent *event)
4386 
4387     Handles paint events passed in the \a event parameter. Will cause
4388     the virtual paintGL() function to be called.
4389 
4390     The widget's rendering context will become the current context and
4391     initializeGL() will be called if it hasn't already been called.
4392 */
4393 
paintEvent(QPaintEvent *)4394 void QGLWidget::paintEvent(QPaintEvent *)
4395 {
4396     if (updatesEnabled()) {
4397         glDraw();
4398         updateOverlayGL();
4399     }
4400 }
4401 
4402 
4403 /*!
4404     \fn void QGLWidget::resizeEvent(QResizeEvent *event)
4405 
4406     Handles resize events that are passed in the \a event parameter.
4407     Calls the virtual function resizeGL().
4408 */
resizeEvent(QResizeEvent * e)4409 void QGLWidget::resizeEvent(QResizeEvent *e)
4410 {
4411     Q_D(QGLWidget);
4412 
4413     QWidget::resizeEvent(e);
4414     if (!isValid())
4415         return;
4416     if (!d->makeCurrent())
4417         return;
4418     if (!d->glcx->initialized())
4419         glInit();
4420     const qreal scaleFactor = (window() && window()->windowHandle()) ?
4421         window()->windowHandle()->devicePixelRatio() : 1.0;
4422 
4423     resizeGL(width() * scaleFactor, height() * scaleFactor);
4424 }
4425 
4426 /*!
4427     Renders the current scene on a pixmap and returns the pixmap.
4428 
4429     You can use this method on both visible and invisible QGLWidget objects.
4430 
4431     Internally the function renders into a framebuffer object and performs pixel
4432     readback. This has a performance penalty, meaning that this function is not
4433     suitable to be called at a high frequency.
4434 
4435     After creating and binding the framebuffer object, the function will call
4436     initializeGL(), resizeGL(), and paintGL(). On the next normal update
4437     initializeGL() and resizeGL() will be triggered again since the size of the
4438     destination pixmap and the QGLWidget's size may differ.
4439 
4440     The size of the pixmap will be \a w pixels wide and \a h pixels high unless
4441     one of these parameters is 0 (the default), in which case the pixmap will
4442     have the same size as the widget.
4443 
4444     Care must be taken when using framebuffer objects in paintGL() in
4445     combination with this function. To switch back to the default framebuffer,
4446     use QGLFramebufferObject::bindDefault(). Binding FBO 0 is wrong since
4447     renderPixmap() uses a custom framebuffer instead of the one provided by the
4448     windowing system.
4449 
4450     \a useContext is ignored. Historically this parameter enabled the usage of
4451     the existing GL context. This is not supported anymore since additional
4452     contexts are never created.
4453 
4454     Overlays are not rendered onto the pixmap.
4455 
4456     If the GL rendering context and the desktop have different bit
4457     depths, the result will most likely look surprising.
4458 
4459     Note that the creation of display lists, modifications of the view
4460     frustum etc. should be done from within initializeGL(). If this is
4461     not done, the temporary QGLContext will not be initialized
4462     properly, and the rendered pixmap may be incomplete/corrupted.
4463 */
4464 
renderPixmap(int w,int h,bool useContext)4465 QPixmap QGLWidget::renderPixmap(int w, int h, bool useContext)
4466 {
4467     Q_UNUSED(useContext);
4468     Q_D(QGLWidget);
4469 
4470     QSize sz = size();
4471     if ((w > 0) && (h > 0))
4472         sz = QSize(w, h);
4473 
4474     QPixmap pm;
4475     if (d->glcx->isValid()) {
4476         d->glcx->makeCurrent();
4477         QGLFramebufferObject fbo(sz, QGLFramebufferObject::CombinedDepthStencil);
4478         fbo.bind();
4479         d->glcx->setInitialized(false);
4480         uint prevDefaultFbo = d->glcx->d_ptr->default_fbo;
4481         d->glcx->d_ptr->default_fbo = fbo.handle();
4482         d->glcx->d_ptr->readback_target_size = sz;
4483         updateGL();
4484         fbo.release();
4485         pm = QPixmap::fromImage(fbo.toImage());
4486         d->glcx->d_ptr->default_fbo = prevDefaultFbo;
4487         d->glcx->setInitialized(false);
4488         d->glcx->d_ptr->readback_target_size = QSize();
4489     }
4490 
4491     return pm;
4492 }
4493 
4494 /*!
4495     Returns an image of the frame buffer. If \a withAlpha is true the
4496     alpha channel is included.
4497 
4498     Depending on your hardware, you can explicitly select which color
4499     buffer to grab with a glReadBuffer() call before calling this
4500     function.
4501 
4502     On QNX the back buffer is not preserved when swapBuffers() is called. The back buffer
4503     where this function reads from, might thus not contain the same content as the front buffer.
4504     In order to retrieve what is currently visible on the screen, swapBuffers()
4505     has to be executed prior to this function call.
4506 */
grabFrameBuffer(bool withAlpha)4507 QImage QGLWidget::grabFrameBuffer(bool withAlpha)
4508 {
4509     makeCurrent();
4510     QImage res;
4511     qreal pixelRatio = devicePixelRatioF();
4512     int w = pixelRatio * width();
4513     int h = pixelRatio * height();
4514     if (format().rgba())
4515         res = qt_gl_read_frame_buffer(QSize(w, h), format().alpha(), withAlpha);
4516     res.setDevicePixelRatio(pixelRatio);
4517     return res;
4518 }
4519 
4520 
4521 
4522 /*!
4523     Initializes OpenGL for this widget's context. Calls the virtual
4524     function initializeGL().
4525 */
4526 
glInit()4527 void QGLWidget::glInit()
4528 {
4529     Q_D(QGLWidget);
4530     if (!isValid())
4531         return;
4532     if (!d->makeCurrent())
4533         return;
4534     initializeGL();
4535     d->glcx->setInitialized(true);
4536 }
4537 
4538 
4539 /*!
4540     Executes the virtual function paintGL().
4541 
4542     The widget's rendering context will become the current context and
4543     initializeGL() will be called if it hasn't already been called.
4544 */
4545 
glDraw()4546 void QGLWidget::glDraw()
4547 {
4548     Q_D(QGLWidget);
4549     if (!isValid())
4550         return;
4551     if (!d->makeCurrent())
4552         return;
4553 #ifndef QT_OPENGL_ES
4554     if (d->glcx->deviceIsPixmap() && !d->glcx->contextHandle()->isOpenGLES())
4555         qgl1_functions()->glDrawBuffer(GL_FRONT);
4556 #endif
4557     QSize readback_target_size = d->glcx->d_ptr->readback_target_size;
4558     if (!d->glcx->initialized()) {
4559         glInit();
4560         const qreal scaleFactor = (window() && window()->windowHandle()) ?
4561             window()->windowHandle()->devicePixelRatio() : 1.0;
4562         int w, h;
4563         if (readback_target_size.isEmpty()) {
4564             w = d->glcx->device()->width() * scaleFactor;
4565             h = d->glcx->device()->height() * scaleFactor;
4566         } else {
4567             w = readback_target_size.width();
4568             h = readback_target_size.height();
4569         }
4570         resizeGL(w, h); // New context needs this "resize"
4571     }
4572     paintGL();
4573     if (doubleBuffer() && readback_target_size.isEmpty()) {
4574         if (d->autoSwap)
4575             swapBuffers();
4576     } else {
4577         qgl_functions()->glFlush();
4578     }
4579 }
4580 
4581 /*!
4582     Convenience function for specifying a drawing color to OpenGL.
4583     Calls glColor4 (in RGBA mode) or glIndex (in color-index mode)
4584     with the color \a c. Applies to this widgets GL context.
4585 
4586     \note This function is not supported on OpenGL/ES 2.0 systems.
4587 
4588     \sa qglClearColor(), QGLContext::currentContext(), QColor
4589 */
4590 
qglColor(const QColor & c) const4591 void QGLWidget::qglColor(const QColor& c) const
4592 {
4593 #if !defined(QT_OPENGL_ES_2)
4594 #ifdef QT_OPENGL_ES
4595     qgl_functions()->glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4596 #else
4597     Q_D(const QGLWidget);
4598     const QGLContext *ctx = QGLContext::currentContext();
4599     if (ctx && !ctx->contextHandle()->isOpenGLES()) {
4600         if (ctx->format().rgba())
4601             qgl1_functions()->glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4602         else if (!d->cmap.isEmpty()) { // QGLColormap in use?
4603             int i = d->cmap.find(c.rgb());
4604             if (i < 0)
4605                 i = d->cmap.findNearest(c.rgb());
4606             qgl1_functions()->glIndexi(i);
4607         } else
4608             qgl1_functions()->glIndexi(ctx->colorIndex(c));
4609     }
4610 #endif //QT_OPENGL_ES
4611 #else
4612     Q_UNUSED(c);
4613 #endif //QT_OPENGL_ES_2
4614 }
4615 
4616 /*!
4617     Convenience function for specifying the clearing color to OpenGL.
4618     Calls glClearColor (in RGBA mode) or glClearIndex (in color-index
4619     mode) with the color \a c. Applies to this widgets GL context.
4620 
4621     \sa qglColor(), QGLContext::currentContext(), QColor
4622 */
4623 
qglClearColor(const QColor & c) const4624 void QGLWidget::qglClearColor(const QColor& c) const
4625 {
4626 #ifdef QT_OPENGL_ES
4627     qgl_functions()->glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4628 #else
4629     Q_D(const QGLWidget);
4630     const QGLContext *ctx = QGLContext::currentContext();
4631     if (ctx && !ctx->contextHandle()->isOpenGLES()) {
4632         if (ctx->format().rgba())
4633             qgl_functions()->glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4634         else if (!d->cmap.isEmpty()) { // QGLColormap in use?
4635             int i = d->cmap.find(c.rgb());
4636             if (i < 0)
4637                 i = d->cmap.findNearest(c.rgb());
4638             qgl1_functions()->glClearIndex(i);
4639         } else {
4640             qgl1_functions()->glClearIndex(ctx->colorIndex(c));
4641         }
4642     } else {
4643         qgl_functions()->glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
4644     }
4645 #endif
4646 }
4647 
4648 
4649 /*!
4650     Converts the image \a img into the unnamed format expected by
4651     OpenGL functions such as glTexImage2D(). The returned image is not
4652     usable as a QImage, but QImage::width(), QImage::height() and
4653     QImage::bits() may be used with OpenGL. The GL format used is
4654     \c GL_RGBA.
4655 
4656     \omit ###
4657 
4658     \l opengl/texture example
4659     The following few lines are from the texture example. Most of the
4660     code is irrelevant, so we just quote the relevant bits:
4661 
4662     \quotefromfile opengl/texture/gltexobj.cpp
4663     \skipto tex1
4664     \printline tex1
4665     \printline gllogo.bmp
4666 
4667     We create \e tex1 (and another variable) for OpenGL, and load a real
4668     image into \e buf.
4669 
4670     \skipto convertToGLFormat
4671     \printline convertToGLFormat
4672 
4673     A few lines later, we convert \e buf into OpenGL format and store it
4674     in \e tex1.
4675 
4676     \skipto glTexImage2D
4677     \printline glTexImage2D
4678     \printline tex1.bits
4679 
4680     Note the dimension restrictions for texture images as described in
4681     the glTexImage2D() documentation. The width must be 2^m + 2*border
4682     and the height 2^n + 2*border where m and n are integers and
4683     border is either 0 or 1.
4684 
4685     Another function in the same example uses \e tex1 with OpenGL.
4686 
4687     \endomit
4688 */
4689 
convertToGLFormat(const QImage & img)4690 QImage QGLWidget::convertToGLFormat(const QImage& img)
4691 {
4692     QImage res(img.size(), QImage::Format_ARGB32);
4693     convertToGLFormatHelper(res, img.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
4694     return res;
4695 }
4696 
4697 
4698 /*!
4699     \fn QGLColormap & QGLWidget::colormap() const
4700 
4701     Returns the colormap for this widget.
4702 
4703     Usually it is only top-level widgets that can have different
4704     colormaps installed. Asking for the colormap of a child widget
4705     will return the colormap for the child's top-level widget.
4706 
4707     If no colormap has been set for this widget, the QGLColormap
4708     returned will be empty.
4709 
4710     \sa setColormap(), QGLColormap::isEmpty()
4711 */
colormap() const4712 const QGLColormap & QGLWidget::colormap() const
4713 {
4714     Q_D(const QGLWidget);
4715     return d->cmap;
4716 }
4717 
4718 /*!
4719     \fn void QGLWidget::setColormap(const QGLColormap & cmap)
4720 
4721     Set the colormap for this widget to \a cmap. Usually it is only
4722     top-level widgets that can have colormaps installed.
4723 
4724     \sa colormap()
4725 */
setColormap(const QGLColormap & c)4726 void QGLWidget::setColormap(const QGLColormap & c)
4727 {
4728     Q_UNUSED(c);
4729 }
4730 
4731 #ifndef QT_OPENGL_ES
4732 
qt_save_gl_state()4733 static void qt_save_gl_state()
4734 {
4735     QOpenGLFunctions *funcs = qgl_functions();
4736     QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
4737 
4738     gl1funcs->glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
4739     gl1funcs->glPushAttrib(GL_ALL_ATTRIB_BITS);
4740     gl1funcs->glMatrixMode(GL_TEXTURE);
4741     gl1funcs->glPushMatrix();
4742     gl1funcs->glLoadIdentity();
4743     gl1funcs->glMatrixMode(GL_PROJECTION);
4744     gl1funcs->glPushMatrix();
4745     gl1funcs->glMatrixMode(GL_MODELVIEW);
4746     gl1funcs->glPushMatrix();
4747 
4748     gl1funcs->glShadeModel(GL_FLAT);
4749     funcs->glDisable(GL_CULL_FACE);
4750     funcs->glDisable(GL_LIGHTING);
4751     funcs->glDisable(GL_STENCIL_TEST);
4752     funcs->glDisable(GL_DEPTH_TEST);
4753     funcs->glEnable(GL_BLEND);
4754     funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
4755 }
4756 
qt_restore_gl_state()4757 static void qt_restore_gl_state()
4758 {
4759     QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
4760 
4761     gl1funcs->glMatrixMode(GL_TEXTURE);
4762     gl1funcs->glPopMatrix();
4763     gl1funcs->glMatrixMode(GL_PROJECTION);
4764     gl1funcs->glPopMatrix();
4765     gl1funcs->glMatrixMode(GL_MODELVIEW);
4766     gl1funcs->glPopMatrix();
4767     gl1funcs->glPopAttrib();
4768     gl1funcs->glPopClientAttrib();
4769 }
4770 
qt_gl_draw_text(QPainter * p,int x,int y,const QString & str,const QFont & font)4771 static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
4772                             const QFont &font)
4773 {
4774     GLfloat color[4];
4775     qgl_functions()->glGetFloatv(GL_CURRENT_COLOR, &color[0]);
4776 
4777     QColor col;
4778     col.setRgbF(color[0], color[1], color[2],color[3]);
4779     QPen old_pen = p->pen();
4780     QFont old_font = p->font();
4781 
4782     p->setPen(col);
4783     p->setFont(font);
4784     p->drawText(x, y, str);
4785 
4786     p->setPen(old_pen);
4787     p->setFont(old_font);
4788 }
4789 
4790 #endif // !QT_OPENGL_ES
4791 
4792 /*!
4793    Renders the string \a str into the GL context of this widget.
4794 
4795    \a x and \a y are specified in window coordinates, with the origin
4796    in the upper left-hand corner of the window. If \a font is not
4797    specified, the currently set application font will be used to
4798    render the string. To change the color of the rendered text you can
4799    use the glColor() call (or the qglColor() convenience function),
4800    just before the renderText() call.
4801 
4802    \note This function clears the stencil buffer.
4803 
4804    \note This function is not supported on OpenGL/ES systems.
4805 
4806    \note This function temporarily disables depth-testing when the
4807    text is drawn.
4808 
4809    \note This function can only be used inside a
4810    QPainter::beginNativePainting()/QPainter::endNativePainting() block
4811    if a painter is active on the QGLWidget.
4812 */
4813 
renderText(int x,int y,const QString & str,const QFont & font)4814 void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font)
4815 {
4816 #ifndef QT_OPENGL_ES
4817     Q_D(QGLWidget);
4818     if (!d->glcx->contextHandle()->isOpenGLES()) {
4819         Q_D(QGLWidget);
4820         if (str.isEmpty() || !isValid())
4821             return;
4822 
4823         QOpenGLFunctions *funcs = qgl_functions();
4824         GLint view[4];
4825         bool use_scissor_testing = funcs->glIsEnabled(GL_SCISSOR_TEST);
4826         if (!use_scissor_testing)
4827             funcs->glGetIntegerv(GL_VIEWPORT, &view[0]);
4828         int width = d->glcx->device()->width();
4829         int height = d->glcx->device()->height();
4830         bool auto_swap = autoBufferSwap();
4831 
4832         QPaintEngine *engine = paintEngine();
4833 
4834         qt_save_gl_state();
4835 
4836         QPainter *p;
4837         bool reuse_painter = false;
4838         if (engine->isActive()) {
4839             reuse_painter = true;
4840             p = engine->painter();
4841 
4842             funcs->glDisable(GL_DEPTH_TEST);
4843             funcs->glViewport(0, 0, width, height);
4844         } else {
4845             setAutoBufferSwap(false);
4846             // disable glClear() as a result of QPainter::begin()
4847             d->disable_clear_on_painter_begin = true;
4848             p = new QPainter(this);
4849         }
4850 
4851         QRect viewport(view[0], view[1], view[2], view[3]);
4852         if (!use_scissor_testing && viewport != rect()) {
4853             // if the user hasn't set a scissor box, we set one that
4854             // covers the current viewport
4855             funcs->glScissor(view[0], view[1], view[2], view[3]);
4856             funcs->glEnable(GL_SCISSOR_TEST);
4857         } else if (use_scissor_testing) {
4858             // use the scissor box set by the user
4859             funcs->glEnable(GL_SCISSOR_TEST);
4860         }
4861 
4862         qt_gl_draw_text(p, x, y, str, font);
4863 
4864         if (!reuse_painter) {
4865             p->end();
4866             delete p;
4867             setAutoBufferSwap(auto_swap);
4868             d->disable_clear_on_painter_begin = false;
4869         }
4870 
4871         qt_restore_gl_state();
4872 
4873         return;
4874     }
4875 #else // QT_OPENGL_ES
4876     Q_UNUSED(x);
4877     Q_UNUSED(y);
4878     Q_UNUSED(str);
4879     Q_UNUSED(font);
4880 #endif
4881     qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
4882 }
4883 
4884 /*! \overload
4885 
4886     \a x, \a y and \a z are specified in scene or object coordinates
4887     relative to the currently set projection and model matrices. This
4888     can be useful if you want to annotate models with text labels and
4889     have the labels move with the model as it is rotated etc.
4890 
4891     \note This function is not supported on OpenGL/ES systems.
4892 
4893     \note If depth testing is enabled before this function is called,
4894     then the drawn text will be depth-tested against the models that
4895     have already been drawn in the scene.  Use \c{glDisable(GL_DEPTH_TEST)}
4896     before calling this function to annotate the models without
4897     depth-testing the text.
4898 
4899     \note This function can only be used inside a
4900     QPainter::beginNativePainting()/QPainter::endNativePainting() block
4901     if a painter is active on the QGLWidget.
4902 */
renderText(double x,double y,double z,const QString & str,const QFont & font)4903 void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font)
4904 {
4905 #ifndef QT_OPENGL_ES
4906     Q_D(QGLWidget);
4907     if (!d->glcx->contextHandle()->isOpenGLES()) {
4908         Q_D(QGLWidget);
4909         if (str.isEmpty() || !isValid())
4910             return;
4911 
4912         QOpenGLFunctions *funcs = qgl_functions();
4913         bool auto_swap = autoBufferSwap();
4914 
4915         int width = d->glcx->device()->width();
4916         int height = d->glcx->device()->height();
4917         GLdouble model[4 * 4], proj[4 * 4];
4918         GLint view[4];
4919         QOpenGLFunctions_1_1 *gl1funcs = qgl1_functions();
4920         gl1funcs->glGetDoublev(GL_MODELVIEW_MATRIX, &model[0]);
4921         gl1funcs->glGetDoublev(GL_PROJECTION_MATRIX, &proj[0]);
4922         funcs->glGetIntegerv(GL_VIEWPORT, &view[0]);
4923         GLdouble win_x = 0, win_y = 0, win_z = 0;
4924         qgluProject(x, y, z, &model[0], &proj[0], &view[0],
4925                     &win_x, &win_y, &win_z);
4926         const int dpr = d->glcx->device()->devicePixelRatioF();
4927         win_x /= dpr;
4928         win_y /= dpr;
4929         win_y = height - win_y; // y is inverted
4930 
4931         QPaintEngine *engine = paintEngine();
4932 
4933         QPainter *p;
4934         bool reuse_painter = false;
4935         bool use_depth_testing = funcs->glIsEnabled(GL_DEPTH_TEST);
4936         bool use_scissor_testing = funcs->glIsEnabled(GL_SCISSOR_TEST);
4937 
4938         qt_save_gl_state();
4939 
4940         if (engine->isActive()) {
4941             reuse_painter = true;
4942             p = engine->painter();
4943         } else {
4944             setAutoBufferSwap(false);
4945             // disable glClear() as a result of QPainter::begin()
4946             d->disable_clear_on_painter_begin = true;
4947             p = new QPainter(this);
4948         }
4949 
4950         QRect viewport(view[0], view[1], view[2], view[3]);
4951         if (!use_scissor_testing && viewport != rect()) {
4952             funcs->glScissor(view[0], view[1], view[2], view[3]);
4953             funcs->glEnable(GL_SCISSOR_TEST);
4954         } else if (use_scissor_testing) {
4955             funcs->glEnable(GL_SCISSOR_TEST);
4956         }
4957         funcs->glViewport(0, 0, width * dpr, height * dpr);
4958         gl1funcs->glAlphaFunc(GL_GREATER, 0.0);
4959         funcs->glEnable(GL_ALPHA_TEST);
4960         if (use_depth_testing)
4961             funcs->glEnable(GL_DEPTH_TEST);
4962 
4963         // The only option in Qt 5 is the shader-based OpenGL 2 paint engine.
4964         // Setting fixed pipeline transformations is futile. Instead, pass the
4965         // extra values directly and let the engine figure the matrices out.
4966         static_cast<QGL2PaintEngineEx *>(p->paintEngine())->setTranslateZ(-2 * win_z);
4967 
4968         qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
4969 
4970         static_cast<QGL2PaintEngineEx *>(p->paintEngine())->setTranslateZ(0);
4971 
4972         if (!reuse_painter) {
4973             p->end();
4974             delete p;
4975             setAutoBufferSwap(auto_swap);
4976             d->disable_clear_on_painter_begin = false;
4977         }
4978 
4979         qt_restore_gl_state();
4980 
4981         return;
4982     }
4983 #else // QT_OPENGL_ES
4984     Q_UNUSED(x);
4985     Q_UNUSED(y);
4986     Q_UNUSED(z);
4987     Q_UNUSED(str);
4988     Q_UNUSED(font);
4989 #endif
4990     qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
4991 }
4992 
format() const4993 QGLFormat QGLWidget::format() const
4994 {
4995     Q_D(const QGLWidget);
4996     return d->glcx->format();
4997 }
4998 
context() const4999 QGLContext *QGLWidget::context() const
5000 {
5001     Q_D(const QGLWidget);
5002     return d->glcx;
5003 }
5004 
doubleBuffer() const5005 bool QGLWidget::doubleBuffer() const
5006 {
5007     Q_D(const QGLWidget);
5008     return d->glcx->d_ptr->glFormat.testOption(QGL::DoubleBuffer);
5009 }
5010 
setAutoBufferSwap(bool on)5011 void QGLWidget::setAutoBufferSwap(bool on)
5012 {
5013     Q_D(QGLWidget);
5014     d->autoSwap = on;
5015 }
5016 
autoBufferSwap() const5017 bool QGLWidget::autoBufferSwap() const
5018 {
5019     Q_D(const QGLWidget);
5020     return d->autoSwap;
5021 }
5022 
5023 /*!
5024     Calls QGLContext:::bindTexture(\a image, \a target, \a format) on the currently
5025     set context.
5026 
5027     \sa deleteTexture()
5028 */
bindTexture(const QImage & image,GLenum target,GLint format)5029 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
5030 {
5031     if (image.isNull())
5032         return 0;
5033 
5034     Q_D(QGLWidget);
5035     return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption);
5036 }
5037 
5038 /*!
5039   \overload
5040   \since 4.6
5041 
5042   The binding \a options are a set of options used to decide how to
5043   bind the texture to the context.
5044  */
bindTexture(const QImage & image,GLenum target,GLint format,QGLContext::BindOptions options)5045 GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options)
5046 {
5047     if (image.isNull())
5048         return 0;
5049 
5050     Q_D(QGLWidget);
5051     return d->glcx->bindTexture(image, target, format, options);
5052 }
5053 
5054 
5055 /*!
5056     Calls QGLContext:::bindTexture(\a pixmap, \a target, \a format) on the currently
5057     set context.
5058 
5059     \sa deleteTexture()
5060 */
bindTexture(const QPixmap & pixmap,GLenum target,GLint format)5061 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
5062 {
5063     if (pixmap.isNull())
5064         return 0;
5065 
5066     Q_D(QGLWidget);
5067     return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
5068 }
5069 
5070 /*!
5071   \overload
5072   \since 4.6
5073 
5074   Generates and binds a 2D GL texture to the current context, based
5075   on \a pixmap. The generated texture id is returned and can be used in
5076 
5077   The binding \a options are a set of options used to decide how to
5078   bind the texture to the context.
5079  */
bindTexture(const QPixmap & pixmap,GLenum target,GLint format,QGLContext::BindOptions options)5080 GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
5081                               QGLContext::BindOptions options)
5082 {
5083     Q_D(QGLWidget);
5084     return d->glcx->bindTexture(pixmap, target, format, options);
5085 }
5086 
5087 /*! \overload
5088 
5089     Calls QGLContext::bindTexture(\a fileName) on the currently set context.
5090 
5091     \sa deleteTexture()
5092 */
bindTexture(const QString & fileName)5093 GLuint QGLWidget::bindTexture(const QString &fileName)
5094 {
5095     Q_D(QGLWidget);
5096     return d->glcx->bindTexture(fileName);
5097 }
5098 
5099 /*!
5100     Calls QGLContext::deleteTexture(\a id) on the currently set
5101     context.
5102 
5103     \sa bindTexture()
5104 */
deleteTexture(GLuint id)5105 void QGLWidget::deleteTexture(GLuint id)
5106 {
5107     Q_D(QGLWidget);
5108     d->glcx->deleteTexture(id);
5109 }
5110 
5111 /*!
5112     \since 4.4
5113 
5114     Calls the corresponding QGLContext::drawTexture() with
5115     \a target, \a textureId, and \a textureTarget for this
5116     widget's context.
5117 */
drawTexture(const QRectF & target,GLuint textureId,GLenum textureTarget)5118 void QGLWidget::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
5119 {
5120     Q_D(QGLWidget);
5121     d->glcx->drawTexture(target, textureId, textureTarget);
5122 }
5123 
5124 /*!
5125     \since 4.4
5126 
5127     Calls the corresponding QGLContext::drawTexture() with
5128     \a point, \a textureId, and \a textureTarget for this
5129     widget's context.
5130 */
drawTexture(const QPointF & point,GLuint textureId,GLenum textureTarget)5131 void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
5132 {
5133     Q_D(QGLWidget);
5134     d->glcx->drawTexture(point, textureId, textureTarget);
5135 }
5136 
Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>,qt_gl_2_engine)5137 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_gl_2_engine)
5138 
5139 Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
5140 {
5141     return qt_gl_2_engine()->engine();
5142 }
5143 
5144 /*!
5145     \internal
5146 
5147     Returns the GL widget's paint engine.
5148 */
paintEngine() const5149 QPaintEngine *QGLWidget::paintEngine() const
5150 {
5151     return qt_qgl_paint_engine();
5152 }
5153 
init(QGLContext * context,const QGLWidget * shareWidget)5154 void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget *shareWidget)
5155 {
5156     Q_Q(QGLWidget);
5157     q->setAttribute(Qt::WA_PaintOnScreen);
5158     q->setAttribute(Qt::WA_NoSystemBackground);
5159     q->setAutoFillBackground(true); // for compatibility
5160 
5161     mustHaveWindowHandle = 1;
5162     q->setAttribute(Qt::WA_NativeWindow);
5163     q->setWindowFlag(Qt::MSWindowsOwnDC);
5164 
5165     initContext(context, shareWidget);
5166 }
5167 
5168 /*
5169   This is the shared initialization for all platforms. Called from QGLWidgetPrivate::init()
5170 */
initContext(QGLContext * context,const QGLWidget * shareWidget)5171 void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWidget)
5172 {
5173     Q_Q(QGLWidget);
5174 
5175     glDevice.setWidget(q);
5176 
5177     glcx = 0;
5178     autoSwap = true;
5179 
5180     if (context && !context->device())
5181         context->setDevice(q);
5182     q->setContext(context, shareWidget ? shareWidget->context() : 0);
5183 
5184     if (!glcx)
5185         glcx = new QGLContext(QGLFormat::defaultFormat(), q);
5186 }
5187 
renderCxPm(QPixmap *)5188 bool QGLWidgetPrivate::renderCxPm(QPixmap*)
5189 {
5190     return false;
5191 }
5192 
5193 /*! \internal
5194   Free up any allocated colormaps. This fn is only called for
5195   top-level widgets.
5196 */
cleanupColormaps()5197 void QGLWidgetPrivate::cleanupColormaps()
5198 {
5199 }
5200 
addShare(const QGLContext * context,const QGLContext * share)5201 void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) {
5202     Q_ASSERT(context && share);
5203     if (context->d_ptr->group == share->d_ptr->group)
5204         return;
5205 
5206     // Make sure 'context' is not already shared with another group of contexts.
5207     Q_ASSERT(context->d_ptr->group->m_refs.loadRelaxed() == 1);
5208 
5209     // Free 'context' group resources and make it use the same resources as 'share'.
5210     QGLContextGroup *group = share->d_ptr->group;
5211     delete context->d_ptr->group;
5212     context->d_ptr->group = group;
5213     group->m_refs.ref();
5214 
5215     // Maintain a list of all the contexts in each group of sharing contexts.
5216     // The list is empty if the "share" context wasn't sharing already.
5217     if (group->m_shares.isEmpty())
5218         group->m_shares.append(share);
5219     group->m_shares.append(context);
5220 }
5221 
removeShare(const QGLContext * context)5222 void QGLContextGroup::removeShare(const QGLContext *context) {
5223     // Remove the context from the group.
5224     QGLContextGroup *group = context->d_ptr->group;
5225     if (group->m_shares.isEmpty())
5226         return;
5227     group->m_shares.removeAll(context);
5228 
5229     // Update context group representative.
5230     Q_ASSERT(group->m_shares.size() != 0);
5231     if (group->m_context == context)
5232         group->m_context = group->m_shares.at(0);
5233 
5234     // If there is only one context left, then make the list empty.
5235     if (group->m_shares.size() == 1)
5236         group->m_shares.clear();
5237 }
5238 
bindCompressedTexture(const QString & fileName,const char * format)5239 QSize QGLTexture::bindCompressedTexture
5240     (const QString& fileName, const char *format)
5241 {
5242     QFile file(fileName);
5243     if (!file.open(QIODevice::ReadOnly))
5244         return QSize();
5245     QByteArray contents = file.readAll();
5246     file.close();
5247     return bindCompressedTexture
5248         (contents.constData(), contents.size(), format);
5249 }
5250 
5251 // PVR header format for container files that store textures compressed
5252 // with the ETC1, PVRTC2, and PVRTC4 encodings.  Format information from the
5253 // PowerVR SDK at http://www.imgtec.com/powervr/insider/powervr-sdk.asp
5254 // "PVRTexTool Reference Manual, version 1.11f".
5255 struct PvrHeader
5256 {
5257     quint32 headerSize;
5258     quint32 height;
5259     quint32 width;
5260     quint32 mipMapCount;
5261     quint32 flags;
5262     quint32 dataSize;
5263     quint32 bitsPerPixel;
5264     quint32 redMask;
5265     quint32 greenMask;
5266     quint32 blueMask;
5267     quint32 alphaMask;
5268     quint32 magic;
5269     quint32 surfaceCount;
5270 };
5271 
5272 #define PVR_MAGIC               0x21525650      // "PVR!" in little-endian
5273 
5274 #define PVR_FORMAT_MASK         0x000000FF
5275 #define PVR_FORMAT_PVRTC2       0x00000018
5276 #define PVR_FORMAT_PVRTC4       0x00000019
5277 #define PVR_FORMAT_ETC1         0x00000036
5278 
5279 #define PVR_HAS_MIPMAPS         0x00000100
5280 #define PVR_TWIDDLED            0x00000200
5281 #define PVR_NORMAL_MAP          0x00000400
5282 #define PVR_BORDER_ADDED        0x00000800
5283 #define PVR_CUBE_MAP            0x00001000
5284 #define PVR_FALSE_COLOR_MIPMAPS 0x00002000
5285 #define PVR_VOLUME_TEXTURE      0x00004000
5286 #define PVR_ALPHA_IN_TEXTURE    0x00008000
5287 #define PVR_VERTICAL_FLIP       0x00010000
5288 
5289 #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
5290 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG      0x8C00
5291 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG      0x8C01
5292 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG     0x8C02
5293 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG     0x8C03
5294 #endif
5295 
5296 #ifndef GL_ETC1_RGB8_OES
5297 #define GL_ETC1_RGB8_OES                        0x8D64
5298 #endif
5299 
canBindCompressedTexture(const char * buf,int len,const char * format,bool * hasAlpha)5300 bool QGLTexture::canBindCompressedTexture
5301     (const char *buf, int len, const char *format, bool *hasAlpha)
5302 {
5303     if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
5304         // Compressed texture loading only supported on little-endian
5305         // systems such as x86 and ARM at the moment.
5306         return false;
5307     }
5308     if (!format) {
5309         // Auto-detect the format from the header.
5310         if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
5311             *hasAlpha = true;
5312             return true;
5313         } else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
5314             const PvrHeader *pvrHeader =
5315                 reinterpret_cast<const PvrHeader *>(buf);
5316             *hasAlpha = (pvrHeader->alphaMask != 0);
5317             return true;
5318         }
5319     } else {
5320         // Validate the format against the header.
5321         if (!qstricmp(format, "DDS")) {
5322             if (len >= 4 && !qstrncmp(buf, "DDS ", 4)) {
5323                 *hasAlpha = true;
5324                 return true;
5325             }
5326         } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
5327             if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4)) {
5328                 const PvrHeader *pvrHeader =
5329                     reinterpret_cast<const PvrHeader *>(buf);
5330                 *hasAlpha = (pvrHeader->alphaMask != 0);
5331                 return true;
5332             }
5333         }
5334     }
5335     return false;
5336 }
5337 
5338 #define ctx QGLContext::currentContext()
5339 
bindCompressedTexture(const char * buf,int len,const char * format)5340 QSize QGLTexture::bindCompressedTexture
5341     (const char *buf, int len, const char *format)
5342 {
5343     if (QSysInfo::ByteOrder != QSysInfo::LittleEndian) {
5344         // Compressed texture loading only supported on little-endian
5345         // systems such as x86 and ARM at the moment.
5346         return QSize();
5347     }
5348     if (!format) {
5349         // Auto-detect the format from the header.
5350         if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
5351             return bindCompressedTextureDDS(buf, len);
5352         else if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
5353             return bindCompressedTexturePVR(buf, len);
5354     } else {
5355         // Validate the format against the header.
5356         if (!qstricmp(format, "DDS")) {
5357             if (len >= 4 && !qstrncmp(buf, "DDS ", 4))
5358                 return bindCompressedTextureDDS(buf, len);
5359         } else if (!qstricmp(format, "PVR") || !qstricmp(format, "ETC1")) {
5360             if (len >= 52 && !qstrncmp(buf + 44, "PVR!", 4))
5361                 return bindCompressedTexturePVR(buf, len);
5362         }
5363     }
5364     return QSize();
5365 }
5366 
bindCompressedTextureDDS(const char * buf,int len)5367 QSize QGLTexture::bindCompressedTextureDDS(const char *buf, int len)
5368 {
5369     // We only support 2D texture loading at present.
5370     if (target != GL_TEXTURE_2D)
5371         return QSize();
5372 
5373     // Bail out if the necessary extension is not present.
5374     if (!qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::DDSTextureCompression)) {
5375         qWarning("QGLContext::bindTexture(): DDS texture compression is not supported.");
5376         return QSize();
5377     }
5378 
5379     const DDSFormat *ddsHeader = reinterpret_cast<const DDSFormat *>(buf + 4);
5380     if (!ddsHeader->dwLinearSize) {
5381         qWarning("QGLContext::bindTexture(): DDS image size is not valid.");
5382         return QSize();
5383     }
5384 
5385     int blockSize = 16;
5386     GLenum format;
5387 
5388     switch(ddsHeader->ddsPixelFormat.dwFourCC) {
5389     case FOURCC_DXT1:
5390         format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
5391         blockSize = 8;
5392         break;
5393     case FOURCC_DXT3:
5394         format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
5395         break;
5396     case FOURCC_DXT5:
5397         format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
5398         break;
5399     default:
5400         qWarning("QGLContext::bindTexture(): DDS image format not supported.");
5401         return QSize();
5402     }
5403 
5404     const GLubyte *pixels =
5405         reinterpret_cast<const GLubyte *>(buf + ddsHeader->dwSize + 4);
5406 
5407     QOpenGLFunctions *funcs = qgl_functions();
5408     funcs->glGenTextures(1, &id);
5409     funcs->glBindTexture(GL_TEXTURE_2D, id);
5410     funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5411     funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5412 
5413     int size;
5414     int offset = 0;
5415     int available = len - int(ddsHeader->dwSize + 4);
5416     int w = ddsHeader->dwWidth;
5417     int h = ddsHeader->dwHeight;
5418 
5419     // load mip-maps
5420     for(int i = 0; i < (int) ddsHeader->dwMipMapCount; ++i) {
5421         if (w == 0) w = 1;
5422         if (h == 0) h = 1;
5423 
5424         size = ((w+3)/4) * ((h+3)/4) * blockSize;
5425         if (size > available)
5426             break;
5427         qgl_extensions()->glCompressedTexImage2D(GL_TEXTURE_2D, i, format, w, h, 0,
5428                                size, pixels + offset);
5429         offset += size;
5430         available -= size;
5431 
5432         // half size for each mip-map level
5433         w = w/2;
5434         h = h/2;
5435     }
5436 
5437     // DDS images are not inverted.
5438     options &= ~QGLContext::InvertedYBindOption;
5439 
5440     return QSize(ddsHeader->dwWidth, ddsHeader->dwHeight);
5441 }
5442 
bindCompressedTexturePVR(const char * buf,int len)5443 QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len)
5444 {
5445     // We only support 2D texture loading at present.  Cube maps later.
5446     if (target != GL_TEXTURE_2D)
5447         return QSize();
5448 
5449     // Determine which texture format we will be loading.
5450     const PvrHeader *pvrHeader = reinterpret_cast<const PvrHeader *>(buf);
5451     GLenum textureFormat;
5452     quint32 minWidth, minHeight;
5453     switch (pvrHeader->flags & PVR_FORMAT_MASK) {
5454     case PVR_FORMAT_PVRTC2:
5455         if (pvrHeader->alphaMask)
5456             textureFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
5457         else
5458             textureFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
5459         minWidth = 16;
5460         minHeight = 8;
5461         break;
5462 
5463     case PVR_FORMAT_PVRTC4:
5464         if (pvrHeader->alphaMask)
5465             textureFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
5466         else
5467             textureFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
5468         minWidth = 8;
5469         minHeight = 8;
5470         break;
5471 
5472     case PVR_FORMAT_ETC1:
5473         textureFormat = GL_ETC1_RGB8_OES;
5474         minWidth = 4;
5475         minHeight = 4;
5476         break;
5477 
5478     default:
5479         qWarning("QGLContext::bindTexture(): PVR image format 0x%x not supported.", int(pvrHeader->flags & PVR_FORMAT_MASK));
5480         return QSize();
5481     }
5482 
5483     // Bail out if the necessary extension is not present.
5484     if (textureFormat == GL_ETC1_RGB8_OES) {
5485         if (!qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::ETC1TextureCompression)) {
5486             qWarning("QGLContext::bindTexture(): ETC1 texture compression is not supported.");
5487             return QSize();
5488         }
5489     } else {
5490         if (!qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::PVRTCTextureCompression)) {
5491             qWarning("QGLContext::bindTexture(): PVRTC texture compression is not supported.");
5492             return QSize();
5493         }
5494     }
5495 
5496     // Boundary check on the buffer size.
5497     quint32 bufferSize = pvrHeader->headerSize + pvrHeader->dataSize;
5498     if (bufferSize > quint32(len)) {
5499         qWarning("QGLContext::bindTexture(): PVR image size is not valid.");
5500         return QSize();
5501     }
5502 
5503     // Create the texture.
5504     QOpenGLFunctions *funcs = qgl_functions();
5505     funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
5506     funcs->glGenTextures(1, &id);
5507     funcs->glBindTexture(GL_TEXTURE_2D, id);
5508     if (pvrHeader->mipMapCount) {
5509         if ((options & QGLContext::LinearFilteringBindOption) != 0) {
5510             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5511             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
5512         } else {
5513             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5514             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
5515         }
5516     } else if ((options & QGLContext::LinearFilteringBindOption) != 0) {
5517         funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5518         funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5519     } else {
5520         funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5521         funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5522     }
5523 
5524     // Load the compressed mipmap levels.
5525     const GLubyte *buffer =
5526         reinterpret_cast<const GLubyte *>(buf + pvrHeader->headerSize);
5527     bufferSize = pvrHeader->dataSize;
5528     quint32 level = 0;
5529     quint32 width = pvrHeader->width;
5530     quint32 height = pvrHeader->height;
5531     while (bufferSize > 0 && level <= pvrHeader->mipMapCount) {
5532         quint32 size =
5533             (qMax(width, minWidth) * qMax(height, minHeight) *
5534              pvrHeader->bitsPerPixel) / 8;
5535         if (size > bufferSize)
5536             break;
5537         qgl_extensions()->glCompressedTexImage2D(GL_TEXTURE_2D, GLint(level), textureFormat,
5538                                GLsizei(width), GLsizei(height), 0,
5539                                GLsizei(size), buffer);
5540         width /= 2;
5541         height /= 2;
5542         buffer += size;
5543         ++level;
5544     }
5545 
5546     // Restore the default pixel alignment for later texture uploads.
5547     funcs->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
5548 
5549     // Set the invert flag for the texture.  The "vertical flip"
5550     // flag in PVR is the opposite sense to our sense of inversion.
5551     options.setFlag(QGLContext::InvertedYBindOption, !(pvrHeader->flags & PVR_VERTICAL_FLIP));
5552 
5553     return QSize(pvrHeader->width, pvrHeader->height);
5554 }
5555 
5556 #undef ctx
5557 
5558 QT_END_NAMESPACE
5559