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