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

Last change on this file since 704 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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