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, ¤t);
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