source: trunk/src/opengl/qgl.cpp@ 1050

Last change on this file since 1050 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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