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

source code of qtbase/src/opengl/qgl.cpp