tests/auto/qgl/tst_qgl.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qgl/tst_qgl.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1923 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qgl.h>
+#include <qglpixelbuffer.h>
+#include <qglframebufferobject.h>
+#include <qglcolormap.h>
+#include <qpaintengine.h>
+
+#include <QGraphicsView>
+#include <QGraphicsProxyWidget>
+#include <QVBoxLayout>
+
+#ifdef QT_BUILD_INTERNAL
+#include <QtOpenGL/private/qgl_p.h>
+#endif
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+class tst_QGL : public QObject
+{
+Q_OBJECT
+
+public:
+    tst_QGL();
+    virtual ~tst_QGL();
+
+private slots:
+    void getSetCheck();
+    void openGLVersionCheck();
+    void graphicsViewClipping();
+    void partialGLWidgetUpdates_data();
+    void partialGLWidgetUpdates();
+    void glWidgetRendering();
+    void glFBORendering();
+    void multipleFBOInterleavedRendering();
+    void glFBOUseInGLWidget();
+    void glPBufferRendering();
+    void glWidgetReparent();
+    void glWidgetRenderPixmap();
+    void stackedFBOs();
+    void colormap();
+    void fboFormat();
+    void testDontCrashOnDanglingResources();
+    void replaceClipping();
+    void clipTest();
+    void destroyFBOAfterContext();
+    void shareRegister();
+};
+
+tst_QGL::tst_QGL()
+{
+}
+
+tst_QGL::~tst_QGL()
+{
+}
+
+class MyGLContext : public QGLContext
+{
+public:
+    MyGLContext(const QGLFormat& format) : QGLContext(format) {}
+    bool windowCreated() const { return QGLContext::windowCreated(); }
+    void setWindowCreated(bool on) { QGLContext::setWindowCreated(on); }
+    bool initialized() const { return QGLContext::initialized(); }
+    void setInitialized(bool on) { QGLContext::setInitialized(on); }
+};
+
+class MyGLWidget : public QGLWidget
+{
+public:
+    MyGLWidget() : QGLWidget() {}
+    bool autoBufferSwap() const { return QGLWidget::autoBufferSwap(); }
+    void setAutoBufferSwap(bool on) { QGLWidget::setAutoBufferSwap(on); }
+};
+
+// Using INT_MIN and INT_MAX will cause failures on systems
+// where "int" is 64-bit, so use the explicit values instead.
+#define TEST_INT_MIN    (-2147483647 - 1)
+#define TEST_INT_MAX    2147483647
+
+// Testing get/set functions
+void tst_QGL::getSetCheck()
+{
+    if (!QGLFormat::hasOpenGL())
+        QSKIP("QGL not supported on this platform", SkipAll);
+
+    QGLFormat obj1;
+    // int QGLFormat::depthBufferSize()
+    // void QGLFormat::setDepthBufferSize(int)
+    QCOMPARE(-1, obj1.depthBufferSize());
+    obj1.setDepthBufferSize(0);
+    QCOMPARE(0, obj1.depthBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -2147483648");
+    obj1.setDepthBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.depthBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setDepthBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -1");
+    obj1.setDepthBufferSize(-1);
+    QCOMPARE(3, obj1.depthBufferSize());
+    obj1.setDepthBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.depthBufferSize());
+
+    // int QGLFormat::accumBufferSize()
+    // void QGLFormat::setAccumBufferSize(int)
+    QCOMPARE(-1, obj1.accumBufferSize());
+    obj1.setAccumBufferSize(0);
+    QCOMPARE(0, obj1.accumBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -2147483648");
+    obj1.setAccumBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.accumBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setAccumBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -1");
+    obj1.setAccumBufferSize(-1);
+    QCOMPARE(3, obj1.accumBufferSize());
+    obj1.setAccumBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.accumBufferSize());
+
+    // int QGLFormat::redBufferSize()
+    // void QGLFormat::setRedBufferSize(int)
+    QCOMPARE(-1, obj1.redBufferSize());
+    obj1.setRedBufferSize(0);
+    QCOMPARE(0, obj1.redBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -2147483648");
+    obj1.setRedBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.redBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setRedBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -1");
+    obj1.setRedBufferSize(-1);
+    QCOMPARE(3, obj1.redBufferSize());
+    obj1.setRedBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.redBufferSize());
+
+    // int QGLFormat::greenBufferSize()
+    // void QGLFormat::setGreenBufferSize(int)
+    QCOMPARE(-1, obj1.greenBufferSize());
+    obj1.setGreenBufferSize(0);
+    QCOMPARE(0, obj1.greenBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -2147483648");
+    obj1.setGreenBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.greenBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setGreenBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -1");
+    obj1.setGreenBufferSize(-1);
+    QCOMPARE(3, obj1.greenBufferSize());
+    obj1.setGreenBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.greenBufferSize());
+
+    // int QGLFormat::blueBufferSize()
+    // void QGLFormat::setBlueBufferSize(int)
+    QCOMPARE(-1, obj1.blueBufferSize());
+    obj1.setBlueBufferSize(0);
+    QCOMPARE(0, obj1.blueBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -2147483648");
+    obj1.setBlueBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.blueBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setBlueBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -1");
+    obj1.setBlueBufferSize(-1);
+    QCOMPARE(3, obj1.blueBufferSize());
+    obj1.setBlueBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.blueBufferSize());
+
+    // int QGLFormat::alphaBufferSize()
+    // void QGLFormat::setAlphaBufferSize(int)
+    QCOMPARE(-1, obj1.alphaBufferSize());
+    QCOMPARE(false, obj1.alpha());
+    QVERIFY(!obj1.testOption(QGL::AlphaChannel));
+    QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
+    obj1.setAlphaBufferSize(0);
+    QCOMPARE(true, obj1.alpha());   // setAlphaBufferSize() enables alpha.
+    QCOMPARE(0, obj1.alphaBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -2147483648");
+    obj1.setAlphaBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.alphaBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setAlphaBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -1");
+    obj1.setAlphaBufferSize(-1);
+    QCOMPARE(3, obj1.alphaBufferSize());
+    obj1.setAlphaBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.alphaBufferSize());
+
+    // int QGLFormat::stencilBufferSize()
+    // void QGLFormat::setStencilBufferSize(int)
+    QCOMPARE(-1, obj1.stencilBufferSize());
+    obj1.setStencilBufferSize(0);
+    QCOMPARE(0, obj1.stencilBufferSize());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -2147483648");
+    obj1.setStencilBufferSize(TEST_INT_MIN);
+    QCOMPARE(0, obj1.stencilBufferSize()); // Makes no sense with a negative buffer size
+    obj1.setStencilBufferSize(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -1");
+    obj1.setStencilBufferSize(-1);
+    QCOMPARE(3, obj1.stencilBufferSize());
+    obj1.setStencilBufferSize(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.stencilBufferSize());
+
+    // bool QGLFormat::sampleBuffers()
+    // void QGLFormat::setSampleBuffers(bool)
+#if !defined(QT_OPENGL_ES_2)
+    QCOMPARE(false, obj1.sampleBuffers());
+    QVERIFY(!obj1.testOption(QGL::SampleBuffers));
+    QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
+#else
+    QCOMPARE(true, obj1.sampleBuffers());
+    QVERIFY(obj1.testOption(QGL::SampleBuffers));
+    QVERIFY(!obj1.testOption(QGL::NoSampleBuffers));
+#endif
+    obj1.setSampleBuffers(false);
+    QCOMPARE(false, obj1.sampleBuffers());
+    QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
+    obj1.setSampleBuffers(true);
+    QCOMPARE(true, obj1.sampleBuffers());
+    QVERIFY(obj1.testOption(QGL::SampleBuffers));
+
+    // int QGLFormat::samples()
+    // void QGLFormat::setSamples(int)
+    QCOMPARE(-1, obj1.samples());
+    obj1.setSamples(0);
+    QCOMPARE(0, obj1.samples());
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -2147483648");
+    obj1.setSamples(TEST_INT_MIN);
+    QCOMPARE(0, obj1.samples());  // Makes no sense with a negative sample size
+    obj1.setSamples(3);
+    QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -1");
+    obj1.setSamples(-1);
+    QCOMPARE(3, obj1.samples());
+    obj1.setSamples(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.samples());
+
+    // int QGLFormat::swapInterval()
+    // void QGLFormat::setSwapInterval(int)
+    QCOMPARE(-1, obj1.swapInterval());
+    obj1.setSwapInterval(0);
+    QCOMPARE(0, obj1.swapInterval());
+    obj1.setSwapInterval(TEST_INT_MIN);
+    QCOMPARE(TEST_INT_MIN, obj1.swapInterval());
+    obj1.setSwapInterval(-1);
+    QCOMPARE(-1, obj1.swapInterval());
+    obj1.setSwapInterval(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.swapInterval());
+
+    // bool QGLFormat::doubleBuffer()
+    // void QGLFormat::setDoubleBuffer(bool)
+    QCOMPARE(true, obj1.doubleBuffer());
+    QVERIFY(obj1.testOption(QGL::DoubleBuffer));
+    QVERIFY(!obj1.testOption(QGL::SingleBuffer));
+    obj1.setDoubleBuffer(false);
+    QCOMPARE(false, obj1.doubleBuffer());
+    QVERIFY(!obj1.testOption(QGL::DoubleBuffer));
+    QVERIFY(obj1.testOption(QGL::SingleBuffer));
+    obj1.setDoubleBuffer(true);
+    QCOMPARE(true, obj1.doubleBuffer());
+    QVERIFY(obj1.testOption(QGL::DoubleBuffer));
+    QVERIFY(!obj1.testOption(QGL::SingleBuffer));
+
+    // bool QGLFormat::depth()
+    // void QGLFormat::setDepth(bool)
+    QCOMPARE(true, obj1.depth());
+    QVERIFY(obj1.testOption(QGL::DepthBuffer));
+    QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
+    obj1.setDepth(false);
+    QCOMPARE(false, obj1.depth());
+    QVERIFY(!obj1.testOption(QGL::DepthBuffer));
+    QVERIFY(obj1.testOption(QGL::NoDepthBuffer));
+    obj1.setDepth(true);
+    QCOMPARE(true, obj1.depth());
+    QVERIFY(obj1.testOption(QGL::DepthBuffer));
+    QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
+
+    // bool QGLFormat::rgba()
+    // void QGLFormat::setRgba(bool)
+    QCOMPARE(true, obj1.rgba());
+    QVERIFY(obj1.testOption(QGL::Rgba));
+    QVERIFY(!obj1.testOption(QGL::ColorIndex));
+    obj1.setRgba(false);
+    QCOMPARE(false, obj1.rgba());
+    QVERIFY(!obj1.testOption(QGL::Rgba));
+    QVERIFY(obj1.testOption(QGL::ColorIndex));
+    obj1.setRgba(true);
+    QCOMPARE(true, obj1.rgba());
+    QVERIFY(obj1.testOption(QGL::Rgba));
+    QVERIFY(!obj1.testOption(QGL::ColorIndex));
+
+    // bool QGLFormat::alpha()
+    // void QGLFormat::setAlpha(bool)
+    QVERIFY(obj1.testOption(QGL::AlphaChannel));
+    QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
+    obj1.setAlpha(false);
+    QCOMPARE(false, obj1.alpha());
+    QVERIFY(!obj1.testOption(QGL::AlphaChannel));
+    QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
+    obj1.setAlpha(true);
+    QCOMPARE(true, obj1.alpha());
+    QVERIFY(obj1.testOption(QGL::AlphaChannel));
+    QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
+
+    // bool QGLFormat::accum()
+    // void QGLFormat::setAccum(bool)
+    QCOMPARE(false, obj1.accum());
+    QVERIFY(!obj1.testOption(QGL::AccumBuffer));
+    QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
+    obj1.setAccum(false);
+    QCOMPARE(false, obj1.accum());
+    QVERIFY(!obj1.testOption(QGL::AccumBuffer));
+    QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
+    obj1.setAccum(true);
+    QCOMPARE(true, obj1.accum());
+    QVERIFY(obj1.testOption(QGL::AccumBuffer));
+    QVERIFY(!obj1.testOption(QGL::NoAccumBuffer));
+
+    // bool QGLFormat::stencil()
+    // void QGLFormat::setStencil(bool)
+    QCOMPARE(true, obj1.stencil());
+    QVERIFY(obj1.testOption(QGL::StencilBuffer));
+    QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
+    obj1.setStencil(false);
+    QCOMPARE(false, obj1.stencil());
+    QVERIFY(!obj1.testOption(QGL::StencilBuffer));
+    QVERIFY(obj1.testOption(QGL::NoStencilBuffer));
+    obj1.setStencil(true);
+    QCOMPARE(true, obj1.stencil());
+    QVERIFY(obj1.testOption(QGL::StencilBuffer));
+    QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
+
+    // bool QGLFormat::stereo()
+    // void QGLFormat::setStereo(bool)
+    QCOMPARE(false, obj1.stereo());
+    QVERIFY(!obj1.testOption(QGL::StereoBuffers));
+    QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
+    obj1.setStereo(false);
+    QCOMPARE(false, obj1.stereo());
+    QVERIFY(!obj1.testOption(QGL::StereoBuffers));
+    QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
+    obj1.setStereo(true);
+    QCOMPARE(true, obj1.stereo());
+    QVERIFY(obj1.testOption(QGL::StereoBuffers));
+    QVERIFY(!obj1.testOption(QGL::NoStereoBuffers));
+
+    // bool QGLFormat::directRendering()
+    // void QGLFormat::setDirectRendering(bool)
+    QCOMPARE(true, obj1.directRendering());
+    QVERIFY(obj1.testOption(QGL::DirectRendering));
+    QVERIFY(!obj1.testOption(QGL::IndirectRendering));
+    obj1.setDirectRendering(false);
+    QCOMPARE(false, obj1.directRendering());
+    QVERIFY(!obj1.testOption(QGL::DirectRendering));
+    QVERIFY(obj1.testOption(QGL::IndirectRendering));
+    obj1.setDirectRendering(true);
+    QCOMPARE(true, obj1.directRendering());
+    QVERIFY(obj1.testOption(QGL::DirectRendering));
+    QVERIFY(!obj1.testOption(QGL::IndirectRendering));
+
+    // bool QGLFormat::overlay()
+    // void QGLFormat::setOverlay(bool)
+    QCOMPARE(false, obj1.hasOverlay());
+    QVERIFY(!obj1.testOption(QGL::HasOverlay));
+    QVERIFY(obj1.testOption(QGL::NoOverlay));
+    obj1.setOverlay(false);
+    QCOMPARE(false, obj1.hasOverlay());
+    QVERIFY(!obj1.testOption(QGL::HasOverlay));
+    QVERIFY(obj1.testOption(QGL::NoOverlay));
+    obj1.setOverlay(true);
+    QCOMPARE(true, obj1.hasOverlay());
+    QVERIFY(obj1.testOption(QGL::HasOverlay));
+    QVERIFY(!obj1.testOption(QGL::NoOverlay));
+
+    // int QGLFormat::plane()
+    // void QGLFormat::setPlane(int)
+    QCOMPARE(0, obj1.plane());
+    obj1.setPlane(0);
+    QCOMPARE(0, obj1.plane());
+    obj1.setPlane(TEST_INT_MIN);
+    QCOMPARE(TEST_INT_MIN, obj1.plane());
+    obj1.setPlane(TEST_INT_MAX);
+    QCOMPARE(TEST_INT_MAX, obj1.plane());
+
+    // operator== and operator!= for QGLFormat
+    QGLFormat format1;
+    QGLFormat format2;
+
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+    format1.setDoubleBuffer(false);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setDoubleBuffer(false);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setDepthBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setDepthBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setAccumBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setAccumBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setRedBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setRedBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setGreenBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setGreenBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setBlueBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setBlueBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setAlphaBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setAlphaBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setStencilBufferSize(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setStencilBufferSize(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setSamples(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setSamples(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setSwapInterval(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setSwapInterval(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    format1.setPlane(8);
+    QVERIFY(!(format1 == format2));
+    QVERIFY(format1 != format2);
+    format2.setPlane(8);
+    QVERIFY(format1 == format2);
+    QVERIFY(!(format1 != format2));
+
+    // Copy constructor and assignment for QGLFormat.
+    QGLFormat format3(format1);
+    QGLFormat format4;
+    QVERIFY(format1 == format3);
+    QVERIFY(format1 != format4);
+    format4 = format1;
+    QVERIFY(format1 == format4);
+
+    // Check that modifying a copy doesn't affect the original.
+    format3.setRedBufferSize(16);
+    format4.setPlane(16);
+    QCOMPARE(format1.redBufferSize(), 8);
+    QCOMPARE(format1.plane(), 8);
+
+    // Check the QGLFormat constructor that takes an option list.
+    QGLFormat format5
+        (QGL::DepthBuffer | QGL::StereoBuffers | QGL::ColorIndex, 3);
+    QVERIFY(format5.depth());
+    QVERIFY(format5.stereo());
+    QVERIFY(format5.doubleBuffer());        // From defaultFormat()
+    QVERIFY(!format5.hasOverlay());         // From defaultFormat()
+    QVERIFY(!format5.rgba());
+    QCOMPARE(format5.plane(), 3);
+
+    // The default format should be the same as QGLFormat().
+    QVERIFY(QGLFormat::defaultFormat() == QGLFormat());
+
+    // Modify the default format and check that it was changed.
+    QGLFormat::setDefaultFormat(format1);
+    QVERIFY(QGLFormat::defaultFormat() == format1);
+
+    // Restore the default format.
+    QGLFormat::setDefaultFormat(QGLFormat());
+    QVERIFY(QGLFormat::defaultFormat() == QGLFormat());
+
+    // Check the default overlay format's expected values.
+    QGLFormat overlay(QGLFormat::defaultOverlayFormat());
+    QCOMPARE(overlay.depthBufferSize(), -1);
+    QCOMPARE(overlay.accumBufferSize(), -1);
+    QCOMPARE(overlay.redBufferSize(), -1);
+    QCOMPARE(overlay.greenBufferSize(), -1);
+    QCOMPARE(overlay.blueBufferSize(), -1);
+    QCOMPARE(overlay.alphaBufferSize(), -1);
+    QCOMPARE(overlay.samples(), -1);
+    QCOMPARE(overlay.swapInterval(), -1);
+    QCOMPARE(overlay.plane(), 1);
+    QVERIFY(!overlay.sampleBuffers());
+    QVERIFY(!overlay.doubleBuffer());
+    QVERIFY(!overlay.depth());
+    QVERIFY(!overlay.rgba());
+    QVERIFY(!overlay.alpha());
+    QVERIFY(!overlay.accum());
+    QVERIFY(!overlay.stencil());
+    QVERIFY(!overlay.stereo());
+    QVERIFY(overlay.directRendering()); // Only option that should be on.
+    QVERIFY(!overlay.hasOverlay());     // Overlay doesn't need an overlay!
+
+    // Modify the default overlay format and check that it was changed.
+    QGLFormat::setDefaultOverlayFormat(format1);
+    QVERIFY(QGLFormat::defaultOverlayFormat() == format1);
+
+    // Restore the default overlay format.
+    QGLFormat::setDefaultOverlayFormat(overlay);
+    QVERIFY(QGLFormat::defaultOverlayFormat() == overlay);
+
+    MyGLContext obj2(obj1);
+    // bool QGLContext::windowCreated()
+    // void QGLContext::setWindowCreated(bool)
+    obj2.setWindowCreated(false);
+    QCOMPARE(false, obj2.windowCreated());
+    obj2.setWindowCreated(true);
+    QCOMPARE(true, obj2.windowCreated());
+
+    // bool QGLContext::initialized()
+    // void QGLContext::setInitialized(bool)
+    obj2.setInitialized(false);
+    QCOMPARE(false, obj2.initialized());
+    obj2.setInitialized(true);
+    QCOMPARE(true, obj2.initialized());
+
+    MyGLWidget obj3;
+    // bool QGLWidget::autoBufferSwap()
+    // void QGLWidget::setAutoBufferSwap(bool)
+    obj3.setAutoBufferSwap(false);
+    QCOMPARE(false, obj3.autoBufferSwap());
+    obj3.setAutoBufferSwap(true);
+    QCOMPARE(true, obj3.autoBufferSwap());
+}
+
+#ifdef QT_BUILD_INTERNAL
+QT_BEGIN_NAMESPACE
+extern QGLFormat::OpenGLVersionFlags qOpenGLVersionFlagsFromString(const QString &versionString);
+QT_END_NAMESPACE
+#endif
+
+void tst_QGL::openGLVersionCheck()
+{
+#ifdef QT_BUILD_INTERNAL
+    if (!QGLFormat::hasOpenGL())
+        QSKIP("QGL not supported on this platform", SkipAll);
+
+    QString versionString;
+    QGLFormat::OpenGLVersionFlags expectedFlag;
+    QGLFormat::OpenGLVersionFlags versionFlag;
+
+    versionString = "1.1 Irix 6.5";
+    expectedFlag = QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "1.2 Microsoft";
+    expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "1.2.1";
+    expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "1.3 NVIDIA";
+    expectedFlag = QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "1.4";
+    expectedFlag = QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "1.5 NVIDIA";
+    expectedFlag = QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "2.0.2 NVIDIA 87.62";
+    expectedFlag = QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "2.1 NVIDIA";
+    expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "2.1";
+    expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "OpenGL ES-CM 1.0 ATI";
+    expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "OpenGL ES-CL 1.0 ATI";
+    expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "OpenGL ES-CM 1.1 ATI";
+    expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "OpenGL ES-CL 1.1 ATI";
+    expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "OpenGL ES 2.0 ATI";
+    expectedFlag = QGLFormat::OpenGL_ES_Version_2_0;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    versionString = "3.0";
+    expectedFlag = QGLFormat::OpenGL_Version_3_0 | QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+    versionFlag = qOpenGLVersionFlagsFromString(versionString);
+    QCOMPARE(versionFlag, expectedFlag);
+
+    QGLWidget glWidget;
+    glWidget.show();
+    glWidget.makeCurrent();
+
+    // This is unfortunately the only test we can make on the actual openGLVersionFlags()
+    // However, the complicated parts are in openGLVersionFlags(const QString &versionString)
+    // tested above
+
+#if defined(QT_OPENGL_ES_1)
+    QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Common_Version_1_0);
+#elif defined(QT_OPENGL_ES_1_CL)
+    QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_CommonLite_Version_1_0);
+#elif defined(QT_OPENGL_ES_2)
+    QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0);
+#else
+    QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_1);
+#endif //defined(QT_OPENGL_ES_1)
+#endif //QT_BUILD_INTERNAL
+}
+
+class UnclippedWidget : public QWidget
+{
+public:
+    void paintEvent(QPaintEvent *)
+    {
+        QPainter p(this);
+        p.fillRect(rect().adjusted(-1000, -1000, 1000, 1000), Qt::black);
+    }
+};
+
+void tst_QGL::graphicsViewClipping()
+{
+    const int size = 64;
+    UnclippedWidget *widget = new UnclippedWidget;
+    widget->setFixedSize(size, size);
+
+    QGraphicsScene scene;
+
+    scene.addWidget(widget)->setPos(0, 0);
+
+    QGraphicsView view(&scene);
+    view.resize(2*size, 2*size);
+
+    QGLWidget *viewport = new QGLWidget;
+    view.setViewport(viewport);
+    view.show();
+
+    if (!viewport->isValid())
+        return;
+
+    scene.setSceneRect(view.viewport()->rect());
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&view);
+#endif
+    QTest::qWait(500);
+
+    QImage image = viewport->grabFrameBuffer();
+    QImage expected = image;
+
+    QPainter p(&expected);
+    p.fillRect(expected.rect(), Qt::white);
+    p.fillRect(QRect(0, 0, size, size), Qt::black);
+    p.end();
+
+    QCOMPARE(image, expected);
+}
+
+void tst_QGL::partialGLWidgetUpdates_data()
+{
+    QTest::addColumn<bool>("doubleBufferedContext");
+    QTest::addColumn<bool>("autoFillBackground");
+    QTest::addColumn<bool>("supportsPartialUpdates");
+
+    QTest::newRow("Double buffered context") << true << true << false;
+    QTest::newRow("Double buffered context without auto-fill background") << true << false << false;
+    QTest::newRow("Single buffered context") << false << true << false;
+    QTest::newRow("Single buffered context without auto-fill background") << false << false << true;
+}
+
+void tst_QGL::partialGLWidgetUpdates()
+{
+    if (!QGLFormat::hasOpenGL())
+        QSKIP("QGL not supported on this platform", SkipAll);
+
+    QFETCH(bool, doubleBufferedContext);
+    QFETCH(bool, autoFillBackground);
+    QFETCH(bool, supportsPartialUpdates);
+
+    class MyGLWidget : public QGLWidget
+    {
+        public:
+            QRegion paintEventRegion;
+            void paintEvent(QPaintEvent *e)
+            {
+                paintEventRegion = e->region();
+            }
+    };
+
+    QGLFormat format = QGLFormat::defaultFormat();
+    format.setDoubleBuffer(doubleBufferedContext);
+    QGLFormat::setDefaultFormat(format);
+
+    MyGLWidget widget;
+    widget.setFixedSize(150, 150);
+    widget.setAutoFillBackground(autoFillBackground);
+    widget.show();
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&widget);
+#endif
+    QTest::qWait(200);
+
+    if (widget.format().doubleBuffer() != doubleBufferedContext)
+        QSKIP("Platform does not support requested format", SkipAll);
+
+    widget.paintEventRegion = QRegion();
+    widget.repaint(50, 50, 50, 50);
+#ifdef Q_WS_MAC
+    // repaint() is not immediate on the Mac; it has to go through the event loop.
+    QTest::qWait(200);
+#endif
+    if (supportsPartialUpdates)
+        QCOMPARE(widget.paintEventRegion, QRegion(50, 50, 50, 50));
+    else
+        QCOMPARE(widget.paintEventRegion, QRegion(widget.rect()));
+}
+
+
+// This tests that rendering to a QGLPBuffer using QPainter works.
+void tst_QGL::glPBufferRendering()
+{
+    if (!QGLPixelBuffer::hasOpenGLPbuffers())
+        QSKIP("QGLPixelBuffer not supported on this platform", SkipSingle);
+
+    QGLPixelBuffer* pbuf = new QGLPixelBuffer(128, 128);
+
+    QPainter p;
+    bool begun = p.begin(pbuf);
+    QVERIFY(begun);
+
+    QPaintEngine::Type engineType = p.paintEngine()->type();
+    QVERIFY(engineType == QPaintEngine::OpenGL || engineType == QPaintEngine::OpenGL2);
+
+    p.fillRect(0, 0, 128, 128, Qt::red);
+    p.fillRect(32, 32, 64, 64, Qt::blue);
+    p.end();
+
+    QImage fb = pbuf->toImage();
+    delete pbuf;
+
+    QImage reference(128, 128, fb.format());
+    p.begin(&reference);
+    p.fillRect(0, 0, 128, 128, Qt::red);
+    p.fillRect(32, 32, 64, 64, Qt::blue);
+    p.end();
+
+    QCOMPARE(fb, reference);
+}
+
+class GLWidget : public QGLWidget
+{
+public:
+    GLWidget(QWidget* p = 0)
+            : QGLWidget(p), beginOk(false), engineType(QPaintEngine::MaxUser) {}
+    bool beginOk;
+    QPaintEngine::Type engineType;
+    void paintGL()
+    {
+        QPainter p;
+        beginOk = p.begin(this);
+        QPaintEngine* pe = p.paintEngine();
+        engineType = pe->type();
+
+        // This test only ensures it's possible to paint onto a QGLWidget. Full
+        // paint engine feature testing is way out of scope!
+
+        p.fillRect(0, 0, width(), height(), Qt::red);
+        // No p.end() or swap buffers, should be done automatically
+    }
+
+};
+
+void tst_QGL::glWidgetRendering()
+{
+    GLWidget w;
+    w.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&w);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(w.beginOk);
+    QVERIFY(w.engineType == QPaintEngine::OpenGL || w.engineType == QPaintEngine::OpenGL2);
+
+    QImage fb = w.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+    QImage reference(fb.size(), QImage::Format_RGB32);
+    reference.fill(0xffff0000);
+
+    QCOMPARE(fb, reference);
+}
+
+// NOTE: This tests that CombinedDepthStencil attachment works by assuming the
+//       GL2 engine is being used and is implemented the same way as it was when
+//       this autotest was written. If this is not the case, there may be some
+//       false-positives: I.e. The test passes when either the depth or stencil
+//       buffer is actually missing. But that's probably ok anyway.
+void tst_QGL::glFBORendering()
+{
+    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);
+
+    QGLWidget glw;
+    glw.makeCurrent();
+
+    // No multisample with combined depth/stencil attachment:
+    QGLFramebufferObjectFormat fboFormat;
+    fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+    // Don't complicate things by using NPOT:
+    QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
+
+    QPainter fboPainter;
+    bool painterBegun = fboPainter.begin(fbo);
+    QVERIFY(painterBegun);
+
+    QPainterPath intersectingPath;
+    intersectingPath.moveTo(0, 0);
+    intersectingPath.lineTo(100, 0);
+    intersectingPath.lineTo(0, 100);
+    intersectingPath.lineTo(100, 100);
+    intersectingPath.closeSubpath();
+
+    QPainterPath trianglePath;
+    trianglePath.moveTo(50, 0);
+    trianglePath.lineTo(100, 100);
+    trianglePath.lineTo(0, 100);
+    trianglePath.closeSubpath();
+
+    fboPainter.fillRect(0, 0, fbo->width(), fbo->height(), Qt::red); // Background
+    fboPainter.translate(14, 14);
+    fboPainter.fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
+    fboPainter.translate(128, 0);
+    fboPainter.setClipPath(trianglePath); // Test depth buffer works
+    fboPainter.setTransform(QTransform()); // reset xform
+    fboPainter.fillRect(0, 0, fbo->width(), fbo->height(), Qt::green);
+    fboPainter.end();
+
+    QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
+    delete fbo;
+
+    // As we're doing more than trivial painting, we can't just compare to
+    // an image rendered with raster. Instead, we sample at well-defined
+    // test-points:
+    QCOMPARE(fb.pixel(39, 64), QColor(Qt::red).rgb());
+    QCOMPARE(fb.pixel(89, 64), QColor(Qt::red).rgb());
+    QCOMPARE(fb.pixel(64, 39), QColor(Qt::blue).rgb());
+    QCOMPARE(fb.pixel(64, 89), QColor(Qt::blue).rgb());
+
+    QCOMPARE(fb.pixel(167, 39), QColor(Qt::red).rgb());
+    QCOMPARE(fb.pixel(217, 39), QColor(Qt::red).rgb());
+    QCOMPARE(fb.pixel(192, 64), QColor(Qt::green).rgb());
+}
+
+
+// Tests multiple QPainters active on different FBOs at the same time, with
+// interleaving painting. Performance-wise, this is sub-optimal, but it still
+// has to work flawlessly
+void tst_QGL::multipleFBOInterleavedRendering()
+{
+    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);
+
+    QGLWidget glw;
+    glw.makeCurrent();
+
+    // No multisample with combined depth/stencil attachment:
+    QGLFramebufferObjectFormat fboFormat;
+    fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+    QGLFramebufferObject *fbo1 = new QGLFramebufferObject(256, 128, fboFormat);
+    QGLFramebufferObject *fbo2 = new QGLFramebufferObject(256, 128, fboFormat);
+    QGLFramebufferObject *fbo3 = new QGLFramebufferObject(256, 128, fboFormat);
+
+    QPainter fbo1Painter;
+    QPainter fbo2Painter;
+    QPainter fbo3Painter;
+
+    QVERIFY(fbo1Painter.begin(fbo1));
+    QVERIFY(fbo2Painter.begin(fbo2));
+    QVERIFY(fbo3Painter.begin(fbo3));
+
+    // Confirm we're using the GL2 engine, as interleaved rendering isn't supported
+    // on the GL1 engine:
+    if (fbo1Painter.paintEngine()->type() != QPaintEngine::OpenGL2)
+        QSKIP("Interleaved GL rendering requires OpenGL 2.0 or higher", SkipSingle);
+
+    QPainterPath intersectingPath;
+    intersectingPath.moveTo(0, 0);
+    intersectingPath.lineTo(100, 0);
+    intersectingPath.lineTo(0, 100);
+    intersectingPath.lineTo(100, 100);
+    intersectingPath.closeSubpath();
+
+    QPainterPath trianglePath;
+    trianglePath.moveTo(50, 0);
+    trianglePath.lineTo(100, 100);
+    trianglePath.lineTo(0, 100);
+    trianglePath.closeSubpath();
+
+    fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::red); // Background
+    fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::green); // Background
+    fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::blue); // Background
+
+    fbo1Painter.translate(14, 14);
+    fbo2Painter.translate(14, 14);
+    fbo3Painter.translate(14, 14);
+
+    fbo1Painter.fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
+    fbo2Painter.fillPath(intersectingPath, Qt::red); // Test stencil buffer works
+    fbo3Painter.fillPath(intersectingPath, Qt::green); // Test stencil buffer works
+
+    fbo1Painter.translate(128, 0);
+    fbo2Painter.translate(128, 0);
+    fbo3Painter.translate(128, 0);
+
+    fbo1Painter.setClipPath(trianglePath);
+    fbo2Painter.setClipPath(trianglePath);
+    fbo3Painter.setClipPath(trianglePath);
+
+    fbo1Painter.setTransform(QTransform()); // reset xform
+    fbo2Painter.setTransform(QTransform()); // reset xform
+    fbo3Painter.setTransform(QTransform()); // reset xform
+
+    fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::green);
+    fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::blue);
+    fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::red);
+
+    fbo1Painter.end();
+    fbo2Painter.end();
+    fbo3Painter.end();
+
+    QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32);
+    QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32);
+    QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32);
+    delete fbo1;
+    delete fbo2;
+    delete fbo3;
+
+    // As we're doing more than trivial painting, we can't just compare to
+    // an image rendered with raster. Instead, we sample at well-defined
+    // test-points:
+    QCOMPARE(fb1.pixel(39, 64), QColor(Qt::red).rgb());
+    QCOMPARE(fb1.pixel(89, 64), QColor(Qt::red).rgb());
+    QCOMPARE(fb1.pixel(64, 39), QColor(Qt::blue).rgb());
+    QCOMPARE(fb1.pixel(64, 89), QColor(Qt::blue).rgb());
+    QCOMPARE(fb1.pixel(167, 39), QColor(Qt::red).rgb());
+    QCOMPARE(fb1.pixel(217, 39), QColor(Qt::red).rgb());
+    QCOMPARE(fb1.pixel(192, 64), QColor(Qt::green).rgb());
+
+    QCOMPARE(fb2.pixel(39, 64), QColor(Qt::green).rgb());
+    QCOMPARE(fb2.pixel(89, 64), QColor(Qt::green).rgb());
+    QCOMPARE(fb2.pixel(64, 39), QColor(Qt::red).rgb());
+    QCOMPARE(fb2.pixel(64, 89), QColor(Qt::red).rgb());
+    QCOMPARE(fb2.pixel(167, 39), QColor(Qt::green).rgb());
+    QCOMPARE(fb2.pixel(217, 39), QColor(Qt::green).rgb());
+    QCOMPARE(fb2.pixel(192, 64), QColor(Qt::blue).rgb());
+
+    QCOMPARE(fb3.pixel(39, 64), QColor(Qt::blue).rgb());
+    QCOMPARE(fb3.pixel(89, 64), QColor(Qt::blue).rgb());
+    QCOMPARE(fb3.pixel(64, 39), QColor(Qt::green).rgb());
+    QCOMPARE(fb3.pixel(64, 89), QColor(Qt::green).rgb());
+    QCOMPARE(fb3.pixel(167, 39), QColor(Qt::blue).rgb());
+    QCOMPARE(fb3.pixel(217, 39), QColor(Qt::blue).rgb());
+    QCOMPARE(fb3.pixel(192, 64), QColor(Qt::red).rgb());
+}
+
+class FBOUseInGLWidget : public QGLWidget
+{
+public:
+    bool widgetPainterBeginOk;
+    bool fboPainterBeginOk;
+    QImage fboImage;
+protected:
+    void paintEvent(QPaintEvent*)
+    {
+        QPainter widgetPainter;
+        widgetPainterBeginOk = widgetPainter.begin(this);
+        QGLFramebufferObjectFormat fboFormat;
+        fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+        QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat);
+
+        QPainter fboPainter;
+        fboPainterBeginOk = fboPainter.begin(fbo);
+        fboPainter.fillRect(0, 0, 128, 128, Qt::red);
+        fboPainter.end();
+        fboImage = fbo->toImage();
+
+        widgetPainter.fillRect(rect(), Qt::blue);
+
+        delete fbo;
+    }
+
+};
+
+void tst_QGL::glFBOUseInGLWidget()
+{
+    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);
+
+    FBOUseInGLWidget w;
+    w.resize(128, 128);
+    w.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&w);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(w.widgetPainterBeginOk);
+    QVERIFY(w.fboPainterBeginOk);
+
+    QImage widgetFB = w.grabFrameBuffer(false);
+    QImage widgetReference(widgetFB.size(), widgetFB.format());
+    widgetReference.fill(0xff0000ff);
+    QCOMPARE(widgetFB, widgetReference);
+
+    QImage fboReference(w.fboImage.size(), w.fboImage.format());
+    fboReference.fill(0xffff0000);
+    QCOMPARE(w.fboImage, fboReference);
+}
+
+void tst_QGL::glWidgetReparent()
+{
+    // Try it as a top-level first:
+    GLWidget *widget = new GLWidget;
+    widget->setGeometry(0, 0, 200, 30);
+    widget->show();
+
+    QWidget grandParentWidget;
+    grandParentWidget.setPalette(Qt::blue);
+    QVBoxLayout grandParentLayout(&grandParentWidget);
+
+    QWidget parentWidget(&grandParentWidget);
+    grandParentLayout.addWidget(&parentWidget);
+    parentWidget.setPalette(Qt::green);
+    parentWidget.setAutoFillBackground(true);
+    QVBoxLayout parentLayout(&parentWidget);
+
+    grandParentWidget.setGeometry(0, 100, 200, 200);
+    grandParentWidget.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(widget);
+    qt_x11_wait_for_window_manager(&parentWidget);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(parentWidget.children().count() == 1); // The layout
+
+    // Now both widgets should be created & shown, time to re-parent:
+    parentLayout.addWidget(widget);
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&parentWidget);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
+    QVERIFY(parentWidget.children().contains(widget));
+    QVERIFY(widget->height() > 30);
+
+    delete widget;
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&parentWidget);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(parentWidget.children().count() == 1); // The layout
+
+    // Now do pretty much the same thing, but don't show the
+    // widget first:
+    widget = new GLWidget;
+    parentLayout.addWidget(widget);
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&parentWidget);
+#endif
+    QTest::qWait(200);
+
+    QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
+    QVERIFY(parentWidget.children().contains(widget));
+    QVERIFY(widget->height() > 30);
+
+    delete widget;
+}
+
+class RenderPixmapWidget : public QGLWidget
+{
+protected:
+    void initializeGL() {
+        // Set some gl state:
+        glClearColor(1.0, 0.0, 0.0, 1.0);
+    }
+
+    void paintGL() {
+        glClear(GL_COLOR_BUFFER_BIT);
+    }
+};
+
+void tst_QGL::glWidgetRenderPixmap()
+{
+    RenderPixmapWidget *w = new RenderPixmapWidget;
+
+    QPixmap pm = w->renderPixmap(100, 100, false);
+
+    delete w;
+
+    QImage fb = pm.toImage().convertToFormat(QImage::Format_RGB32);
+    QImage reference(fb.size(), QImage::Format_RGB32);
+    reference.fill(0xffff0000);
+
+    QCOMPARE(fb, reference);
+}
+
+
+// When using multiple FBOs at the same time, unbinding one FBO should re-bind the
+// previous. I.e. It should be possible to have a stack of FBOs where pop'ing there
+// top re-binds the one underneeth.
+void tst_QGL::stackedFBOs()
+{
+    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);
+
+    QGLWidget glw;
+    glw.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&glw);
+#endif
+    QTest::qWait(200);
+
+    glw.makeCurrent();
+
+    // No multisample with combined depth/stencil attachment:
+    QGLFramebufferObjectFormat fboFormat;
+    fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+    // Don't complicate things by using NPOT:
+    QGLFramebufferObject *fbo1 = new QGLFramebufferObject(128, 128, fboFormat);
+    QGLFramebufferObject *fbo2 = new QGLFramebufferObject(128, 128, fboFormat);
+    QGLFramebufferObject *fbo3 = new QGLFramebufferObject(128, 128, fboFormat);
+
+    glClearColor(1.0, 0.0, 1.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    fbo1->bind();
+        glClearColor(1.0, 0.0, 0.0, 1.0);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        fbo2->bind();
+            glClearColor(0.0, 1.0, 0.0, 1.0);
+            glClear(GL_COLOR_BUFFER_BIT);
+
+            fbo3->bind();
+                glClearColor(0.0, 0.0, 1.0, 1.0);
+                glClear(GL_COLOR_BUFFER_BIT);
+                glScissor(32, 32, 64, 64);
+                glEnable(GL_SCISSOR_TEST);
+                glClearColor(0.0, 1.0, 1.0, 1.0);
+                glClear(GL_COLOR_BUFFER_BIT);
+            fbo3->release();
+
+            // Scissor rect & test should be left untouched by the fbo release...
+            glClearColor(0.0, 0.0, 0.0, 1.0);
+            glClear(GL_COLOR_BUFFER_BIT);
+        fbo2->release();
+
+        glClearColor(1.0, 1.0, 1.0, 1.0);
+        glClear(GL_COLOR_BUFFER_BIT);
+    fbo1->release();
+
+    glClearColor(1.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glw.swapBuffers();
+
+    QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+    QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32);
+    QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32);
+    QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32);
+
+    delete fbo1;
+    delete fbo2;
+    delete fbo3;
+
+    QImage widgetReference(widgetFB.size(), widgetFB.format());
+    QImage fb1Reference(fb1.size(), fb1.format());
+    QImage fb2Reference(fb2.size(), fb2.format());
+    QImage fb3Reference(fb3.size(), fb3.format());
+
+    QPainter widgetReferencePainter(&widgetReference);
+    QPainter fb1ReferencePainter(&fb1Reference);
+    QPainter fb2ReferencePainter(&fb2Reference);
+    QPainter fb3ReferencePainter(&fb3Reference);
+
+    widgetReferencePainter.fillRect(0, 0, widgetReference.width(), widgetReference.height(), Qt::magenta);
+    fb1ReferencePainter.fillRect(0, 0, fb1Reference.width(), fb1Reference.height(), Qt::red);
+    fb2ReferencePainter.fillRect(0, 0, fb2Reference.width(), fb2Reference.height(), Qt::green);
+    fb3ReferencePainter.fillRect(0, 0, fb3Reference.width(), fb3Reference.height(), Qt::blue);
+
+    // Flip y-coords to match GL for the widget (which can be any size)
+    widgetReferencePainter.fillRect(32, glw.height() - 96, 64, 64, Qt::yellow);
+    fb1ReferencePainter.fillRect(32, 32, 64, 64, Qt::white);
+    fb2ReferencePainter.fillRect(32, 32, 64, 64, Qt::black);
+    fb3ReferencePainter.fillRect(32, 32, 64, 64, Qt::cyan);
+
+    widgetReferencePainter.end();
+    fb1ReferencePainter.end();
+    fb2ReferencePainter.end();
+    fb3ReferencePainter.end();
+
+    QCOMPARE(widgetFB, widgetReference);
+    QCOMPARE(fb1, fb1Reference);
+    QCOMPARE(fb2, fb2Reference);
+    QCOMPARE(fb3, fb3Reference);
+}
+
+
+class ColormapExtended : public QGLColormap
+{
+public:
+    ColormapExtended() {}
+
+    Qt::HANDLE handle() { return QGLColormap::handle(); }
+    void setHandle(Qt::HANDLE handle) { QGLColormap::setHandle(handle); }
+};
+
+void tst_QGL::colormap()
+{
+    // Check the properties of the default empty colormap.
+    QGLColormap cmap1;
+    QVERIFY(cmap1.isEmpty());
+    QCOMPARE(cmap1.size(), 0);
+    QVERIFY(cmap1.entryRgb(0) == 0);
+    QVERIFY(cmap1.entryRgb(-1) == 0);
+    QVERIFY(cmap1.entryRgb(100) == 0);
+    QVERIFY(!cmap1.entryColor(0).isValid());
+    QVERIFY(!cmap1.entryColor(-1).isValid());
+    QVERIFY(!cmap1.entryColor(100).isValid());
+    QCOMPARE(cmap1.find(qRgb(255, 0, 0)), -1);
+    QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), -1);
+
+    // Set an entry and re-test.
+    cmap1.setEntry(56, qRgb(255, 0, 0));
+    // The colormap is still considered "empty" even though it
+    // has entries in it now.  The isEmpty() method is used to
+    // detect when the colormap is in use by a GL widget,
+    // not to detect when it is empty!
+    QVERIFY(cmap1.isEmpty());
+    QCOMPARE(cmap1.size(), 256);
+    QVERIFY(cmap1.entryRgb(0) == 0);
+    QVERIFY(cmap1.entryColor(0) == QColor(0, 0, 0, 255));
+    QVERIFY(cmap1.entryRgb(56) == qRgb(255, 0, 0));
+    QVERIFY(cmap1.entryColor(56) == QColor(255, 0, 0, 255));
+    QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
+    QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
+
+    // Set some more entries.
+    static QRgb const colors[] = {
+        qRgb(255, 0, 0),
+        qRgb(0, 255, 0),
+        qRgb(255, 255, 255),
+        qRgb(0, 0, 255),
+        qRgb(0, 0, 0)
+    };
+    cmap1.setEntry(57, QColor(0, 255, 0));
+    cmap1.setEntries(3, colors + 2, 58);
+    cmap1.setEntries(5, colors, 251);
+    int idx;
+    for (idx = 0; idx < 5; ++idx) {
+        QVERIFY(cmap1.entryRgb(56 + idx) == colors[idx]);
+        QVERIFY(cmap1.entryColor(56 + idx) == QColor(colors[idx]));
+        QVERIFY(cmap1.entryRgb(251 + idx) == colors[idx]);
+        QVERIFY(cmap1.entryColor(251 + idx) == QColor(colors[idx]));
+    }
+    QCOMPARE(cmap1.size(), 256);
+
+    // Perform color lookups.
+    QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
+    QCOMPARE(cmap1.find(qRgb(0, 0, 0)), 60); // Actually finds 0, 0, 0, 255.
+    QCOMPARE(cmap1.find(qRgba(0, 0, 0, 0)), 0);
+    QCOMPARE(cmap1.find(qRgb(0, 255, 0)), 57);
+    QCOMPARE(cmap1.find(qRgb(255, 255, 255)), 58);
+    QCOMPARE(cmap1.find(qRgb(0, 0, 255)), 59);
+    QCOMPARE(cmap1.find(qRgb(140, 0, 0)), -1);
+    QCOMPARE(cmap1.find(qRgb(0, 140, 0)), -1);
+    QCOMPARE(cmap1.find(qRgb(0, 0, 140)), -1);
+    QCOMPARE(cmap1.find(qRgb(64, 0, 0)), -1);
+    QCOMPARE(cmap1.find(qRgb(0, 64, 0)), -1);
+    QCOMPARE(cmap1.find(qRgb(0, 0, 64)), -1);
+    QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 0, 0)), 60);
+    QCOMPARE(cmap1.findNearest(qRgba(0, 0, 0, 0)), 0);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 255, 0)), 57);
+    QCOMPARE(cmap1.findNearest(qRgb(255, 255, 255)), 58);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 0, 255)), 59);
+    QCOMPARE(cmap1.findNearest(qRgb(140, 0, 0)), 56);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 140, 0)), 57);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 0, 140)), 59);
+    QCOMPARE(cmap1.findNearest(qRgb(64, 0, 0)), 0);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 64, 0)), 0);
+    QCOMPARE(cmap1.findNearest(qRgb(0, 0, 64)), 0);
+
+    // Make some copies of the colormap and check that they are the same.
+    QGLColormap cmap2(cmap1);
+    QGLColormap cmap3;
+    cmap3 = cmap1;
+    QVERIFY(cmap2.isEmpty());
+    QVERIFY(cmap3.isEmpty());
+    QCOMPARE(cmap2.size(), 256);
+    QCOMPARE(cmap3.size(), 256);
+    for (idx = 0; idx < 256; ++idx) {
+        QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
+        QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
+    }
+
+    // Modify an entry in one of the copies and recheck the original.
+    cmap2.setEntry(45, qRgb(255, 0, 0));
+    for (idx = 0; idx < 256; ++idx) {
+        if (idx != 45)
+            QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
+        else
+            QCOMPARE(cmap2.entryRgb(45), qRgb(255, 0, 0));
+        QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
+    }
+
+    // Check that setting the handle will cause isEmpty() to work right.
+    ColormapExtended cmap4;
+    cmap4.setEntry(56, qRgb(255, 0, 0));
+    QVERIFY(cmap4.isEmpty());
+    QCOMPARE(cmap4.size(), 256);
+    cmap4.setHandle(Qt::HANDLE(42));
+    QVERIFY(cmap4.handle() == Qt::HANDLE(42));
+    QVERIFY(!cmap4.isEmpty());
+    QCOMPARE(cmap4.size(), 256);
+}
+
+#ifndef QT_OPENGL_ES
+#define DEFAULT_FORMAT GL_RGBA8
+#else
+#define DEFAULT_FORMAT GL_RGBA
+#endif
+
+#ifndef GL_TEXTURE_3D
+#define GL_TEXTURE_3D 0x806F
+#endif
+
+#ifndef GL_RGB16
+#define GL_RGB16 0x8054
+#endif
+
+void tst_QGL::fboFormat()
+{
+    // Check the initial conditions.
+    QGLFramebufferObjectFormat format1;
+    QCOMPARE(format1.samples(), 0);
+    QVERIFY(format1.attachment() == QGLFramebufferObject::NoAttachment);
+    QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_2D));
+    QCOMPARE(int(format1.internalTextureFormat()), int(DEFAULT_FORMAT));
+
+    // Modify the values and re-check.
+    format1.setSamples(8);
+    format1.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+    format1.setTextureTarget(GL_TEXTURE_3D);
+    format1.setInternalTextureFormat(GL_RGB16);
+    QCOMPARE(format1.samples(), 8);
+    QVERIFY(format1.attachment() == QGLFramebufferObject::CombinedDepthStencil);
+    QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
+    QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
+
+    // Make copies and check that they are the same.
+    QGLFramebufferObjectFormat format2(format1);
+    QGLFramebufferObjectFormat format3;
+    QCOMPARE(format2.samples(), 8);
+    QVERIFY(format2.attachment() == QGLFramebufferObject::CombinedDepthStencil);
+    QCOMPARE(int(format2.textureTarget()), int(GL_TEXTURE_3D));
+    QCOMPARE(int(format2.internalTextureFormat()), int(GL_RGB16));
+    format3 = format1;
+    QCOMPARE(format3.samples(), 8);
+    QVERIFY(format3.attachment() == QGLFramebufferObject::CombinedDepthStencil);
+    QCOMPARE(int(format3.textureTarget()), int(GL_TEXTURE_3D));
+    QCOMPARE(int(format3.internalTextureFormat()), int(GL_RGB16));
+
+    // Modify the copies and check that the original is unchanged.
+    format2.setSamples(9);
+    format3.setTextureTarget(GL_TEXTURE_2D);
+    QCOMPARE(format1.samples(), 8);
+    QVERIFY(format1.attachment() == QGLFramebufferObject::CombinedDepthStencil);
+    QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
+    QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
+
+    // operator== and operator!= for QGLFramebufferObjectFormat.
+    QGLFramebufferObjectFormat format1c;
+    QGLFramebufferObjectFormat format2c;
+
+    QVERIFY(format1c == format2c);
+    QVERIFY(!(format1c != format2c));
+    format1c.setSamples(8);
+    QVERIFY(!(format1c == format2c));
+    QVERIFY(format1c != format2c);
+    format2c.setSamples(8);
+    QVERIFY(format1c == format2c);
+    QVERIFY(!(format1c != format2c));
+
+    format1c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+    QVERIFY(!(format1c == format2c));
+    QVERIFY(format1c != format2c);
+    format2c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+    QVERIFY(format1c == format2c);
+    QVERIFY(!(format1c != format2c));
+
+    format1c.setTextureTarget(GL_TEXTURE_3D);
+    QVERIFY(!(format1c == format2c));
+    QVERIFY(format1c != format2c);
+    format2c.setTextureTarget(GL_TEXTURE_3D);
+    QVERIFY(format1c == format2c);
+    QVERIFY(!(format1c != format2c));
+
+    format1c.setInternalTextureFormat(GL_RGB16);
+    QVERIFY(!(format1c == format2c));
+    QVERIFY(format1c != format2c);
+    format2c.setInternalTextureFormat(GL_RGB16);
+    QVERIFY(format1c == format2c);
+    QVERIFY(!(format1c != format2c));
+
+    QGLFramebufferObjectFormat format3c(format1c);
+    QGLFramebufferObjectFormat format4c;
+    QVERIFY(format1c == format3c);
+    QVERIFY(!(format1c != format3c));
+    format3c.setInternalTextureFormat(DEFAULT_FORMAT);
+    QVERIFY(!(format1c == format3c));
+    QVERIFY(format1c != format3c);
+
+    format4c = format1c;
+    QVERIFY(format1c == format4c);
+    QVERIFY(!(format1c != format4c));
+    format4c.setInternalTextureFormat(DEFAULT_FORMAT);
+    QVERIFY(!(format1c == format4c));
+    QVERIFY(format1c != format4c);
+}
+
+void tst_QGL::testDontCrashOnDanglingResources()
+{
+    // We have a number of Q_GLOBAL_STATICS inside the QtOpenGL
+    // library. This test is verify that we don't crash as a result of
+    // them calling into libgl on application shutdown.
+    QWidget *widget = new UnclippedWidget();
+    widget->show();
+    qApp->processEvents();
+    widget->hide();
+}
+
+class ReplaceClippingGLWidget : public QGLWidget
+{
+public:
+    void paint(QPainter *painter)
+    {
+        painter->fillRect(rect(), Qt::white);
+
+        QPainterPath path;
+        path.addRect(0, 0, 100, 100);
+        path.addRect(50, 50, 100, 100);
+
+        painter->setClipRect(0, 0, 150, 150);
+        painter->fillPath(path, Qt::red);
+
+        painter->translate(150, 150);
+        painter->setClipRect(0, 0, 150, 150);
+        painter->fillPath(path, Qt::red);
+    }
+
+protected:
+    void paintEvent(QPaintEvent*)
+    {
+        // clear the stencil with junk
+        glStencilMask(0xFFFF);
+        glClearStencil(0xFFFF);
+        glDisable(GL_STENCIL_TEST);
+        glDisable(GL_SCISSOR_TEST);
+        glClear(GL_STENCIL_BUFFER_BIT);
+
+        QPainter painter(this);
+        paint(&painter);
+    }
+};
+
+void tst_QGL::replaceClipping()
+{
+    ReplaceClippingGLWidget glw;
+    glw.resize(300, 300);
+    glw.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&glw);
+#endif
+    QTest::qWait(200);
+
+    QImage reference(300, 300, QImage::Format_RGB32);
+    QPainter referencePainter(&reference);
+    glw.paint(&referencePainter);
+    referencePainter.end();
+
+    const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+
+    QCOMPARE(widgetFB, reference);
+}
+
+class ClipTestGLWidget : public QGLWidget
+{
+public:
+    void paint(QPainter *painter)
+    {
+        painter->fillRect(rect(), Qt::white);
+        painter->setClipRect(10, 10, width()-20, height()-20);
+        painter->fillRect(rect(), Qt::cyan);
+
+        painter->save();
+        painter->setClipRect(10, 10, 100, 100, Qt::IntersectClip);
+
+        painter->fillRect(rect(), Qt::blue);
+
+        painter->save();
+        painter->setClipRect(10, 10, 50, 50, Qt::IntersectClip);
+        painter->fillRect(rect(), Qt::red);
+        painter->restore();
+        painter->fillRect(0, 0, 40, 40, Qt::white);
+        painter->save();
+
+        painter->setClipRect(0, 0, 35, 35, Qt::IntersectClip);
+        painter->fillRect(rect(), Qt::black);
+        painter->restore();
+
+        painter->fillRect(0, 0, 30, 30, Qt::magenta);
+
+        painter->save();
+        painter->setClipRect(60, 10, 50, 50, Qt::ReplaceClip);
+        painter->fillRect(rect(), Qt::green);
+        painter->restore();
+
+        painter->save();
+        painter->setClipRect(0, 60, 60, 25, Qt::IntersectClip);
+        painter->setClipRect(60, 60, 50, 25, Qt::UniteClip);
+        painter->fillRect(rect(), Qt::yellow);
+        painter->restore();
+
+        painter->restore();
+
+        painter->translate(100, 100);
+
+        {
+            QPainterPath path;
+            path.addRect(10, 10, 100, 100);
+            path.addRect(10, 10, 10, 10);
+            painter->setClipPath(path, Qt::IntersectClip);
+        }
+
+        painter->fillRect(rect(), Qt::blue);
+
+        painter->save();
+        {
+            QPainterPath path;
+            path.addRect(10, 10, 50, 50);
+            path.addRect(10, 10, 10, 10);
+            painter->setClipPath(path, Qt::IntersectClip);
+        }
+        painter->fillRect(rect(), Qt::red);
+        painter->restore();
+        painter->fillRect(0, 0, 40, 40, Qt::white);
+        painter->save();
+
+        {
+            QPainterPath path;
+            path.addRect(0, 0, 35, 35);
+            path.addRect(10, 10, 10, 10);
+            painter->setClipPath(path, Qt::IntersectClip);
+        }
+        painter->fillRect(rect(), Qt::black);
+        painter->restore();
+
+        painter->fillRect(0, 0, 30, 30, Qt::magenta);
+
+        painter->save();
+        {
+            QPainterPath path;
+            path.addRect(60, 10, 50, 50);
+            path.addRect(10, 10, 10, 10);
+            painter->setClipPath(path, Qt::ReplaceClip);
+        }
+        painter->fillRect(rect(), Qt::green);
+        painter->restore();
+
+        painter->save();
+        {
+            QPainterPath path;
+            path.addRect(0, 60, 60, 25);
+            path.addRect(10, 10, 10, 10);
+            painter->setClipPath(path, Qt::IntersectClip);
+        }
+        painter->setClipRect(60, 60, 50, 25, Qt::UniteClip);
+        painter->fillRect(rect(), Qt::yellow);
+        painter->restore();
+    }
+
+protected:
+    void paintEvent(QPaintEvent*)
+    {
+        QPainter painter(this);
+        paint(&painter);
+    }
+};
+
+void tst_QGL::clipTest()
+{
+    ClipTestGLWidget glw;
+    glw.resize(220, 220);
+    glw.show();
+
+#ifdef Q_WS_X11
+    qt_x11_wait_for_window_manager(&glw);
+#endif
+    QTest::qWait(200);
+
+    QImage reference(glw.size(), QImage::Format_RGB32);
+    QPainter referencePainter(&reference);
+    glw.paint(&referencePainter);
+    referencePainter.end();
+
+    const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+
+    QCOMPARE(widgetFB, reference);
+}
+
+void tst_QGL::destroyFBOAfterContext()
+{
+    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);
+
+    QGLWidget *glw = new QGLWidget();
+    glw->makeCurrent();
+
+    // No multisample with combined depth/stencil attachment:
+    QGLFramebufferObjectFormat fboFormat;
+    fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+    // Don't complicate things by using NPOT:
+    QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
+
+    // The handle should be valid until the context is destroyed.
+    QVERIFY(fbo->handle() != 0);
+    QVERIFY(fbo->isValid());
+
+    delete glw;
+
+    // The handle should now be zero.
+    QVERIFY(fbo->handle() == 0);
+    QVERIFY(!fbo->isValid());
+
+    delete fbo;
+}
+
+#ifdef QT_BUILD_INTERNAL
+
+class tst_QGLResource : public QObject
+{
+    Q_OBJECT
+public:
+    tst_QGLResource(QObject *parent = 0) : QObject(parent) {}
+    ~tst_QGLResource() { ++deletions; }
+
+    static int deletions;
+};
+
+int tst_QGLResource::deletions = 0;
+
+static void qt_shared_test_free(void *data)
+{
+    delete reinterpret_cast<tst_QGLResource *>(data);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_test, (qt_shared_test_free))
+
+#endif
+
+void tst_QGL::shareRegister()
+{
+#ifdef QT_BUILD_INTERNAL
+    QGLShareRegister *shareReg = qgl_share_reg();
+    QVERIFY(shareReg != 0);
+
+    // Create a context.
+    QGLWidget *glw1 = new QGLWidget();
+    glw1->makeCurrent();
+
+    // Nothing should be sharing with glw1's context yet.
+    QList<const QGLContext *> list;
+    list = shareReg->shares(glw1->context());
+    QCOMPARE(list.size(), 0);
+
+    // Create a guard for the first context.
+    QGLSharedResourceGuard guard(glw1->context());
+    QVERIFY(guard.id() == 0);
+    guard.setId(3);
+    QVERIFY(guard.id() == 3);
+
+    // Add a resource to the first context.
+    tst_QGLResource *res1 = new tst_QGLResource();
+    QVERIFY(!qt_shared_test()->value(glw1->context()));
+    qt_shared_test()->insert(glw1->context(), res1);
+    QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
+
+    // Create another context that shares with the first.
+    QGLWidget *glw2 = new QGLWidget(0, glw1);
+    if (!glw2->isSharing()) {
+        delete glw2;
+        delete glw1;
+        QSKIP("Context sharing is not supported", SkipSingle);
+    }
+    QVERIFY(glw1->context() != glw2->context());
+
+    // Check that the first context's resource is also on the second.
+    QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
+    QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
+
+    // Guard should still be the same.
+    QVERIFY(guard.context() == glw1->context());
+    QVERIFY(guard.id() == 3);
+
+    // Now there are two items in the share lists.
+    list = shareReg->shares(glw1->context());
+    QCOMPARE(list.size(), 2);
+    QVERIFY(list.contains(glw1->context()));
+    QVERIFY(list.contains(glw2->context()));
+    list = shareReg->shares(glw2->context());
+    QCOMPARE(list.size(), 2);
+    QVERIFY(list.contains(glw1->context()));
+    QVERIFY(list.contains(glw2->context()));
+
+    // Check the sharing relationships.
+    QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
+    QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
+    QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
+    QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
+    QVERIFY(!QGLContext::areSharing(0, glw2->context()));
+    QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
+    QVERIFY(!QGLContext::areSharing(0, 0));
+
+    // Create a third context, not sharing with the others.
+    QGLWidget *glw3 = new QGLWidget();
+
+    // Create a guard on the standalone context.
+    QGLSharedResourceGuard guard3(glw3->context());
+    guard3.setId(5);
+
+    // Add a resource to the third context.
+    tst_QGLResource *res3 = new tst_QGLResource();
+    QVERIFY(!qt_shared_test()->value(glw3->context()));
+    qt_shared_test()->insert(glw3->context(), res3);
+    QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
+    QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
+    QVERIFY(qt_shared_test()->value(glw3->context()) == res3);
+
+    // First two should still be sharing, but third is in its own list.
+    list = shareReg->shares(glw1->context());
+    QCOMPARE(list.size(), 2);
+    QVERIFY(list.contains(glw1->context()));
+    QVERIFY(list.contains(glw2->context()));
+    list = shareReg->shares(glw2->context());
+    QCOMPARE(list.size(), 2);
+    QVERIFY(list.contains(glw1->context()));
+    QVERIFY(list.contains(glw2->context()));
+    list = shareReg->shares(glw3->context());
+    QCOMPARE(list.size(), 0);
+
+    // Check the sharing relationships again.
+    QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
+    QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
+    QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
+    QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
+    QVERIFY(!QGLContext::areSharing(glw1->context(), glw3->context()));
+    QVERIFY(!QGLContext::areSharing(glw2->context(), glw3->context()));
+    QVERIFY(!QGLContext::areSharing(glw3->context(), glw1->context()));
+    QVERIFY(!QGLContext::areSharing(glw3->context(), glw2->context()));
+    QVERIFY(QGLContext::areSharing(glw3->context(), glw3->context()));
+    QVERIFY(!QGLContext::areSharing(0, glw2->context()));
+    QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
+    QVERIFY(!QGLContext::areSharing(0, glw3->context()));
+    QVERIFY(!QGLContext::areSharing(glw3->context(), 0));
+    QVERIFY(!QGLContext::areSharing(0, 0));
+
+    // Shared guard should still be the same.
+    QVERIFY(guard.context() == glw1->context());
+    QVERIFY(guard.id() == 3);
+
+    // Delete the first context.
+    delete glw1;
+
+    // The first context's resource should transfer to the second context.
+    QCOMPARE(tst_QGLResource::deletions, 0);
+    QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
+    QVERIFY(qt_shared_test()->value(glw3->context()) == res3);
+
+    // Shared guard should now be the second context, with the id the same.
+    QVERIFY(guard.context() == glw2->context());
+    QVERIFY(guard.id() == 3);
+    QVERIFY(guard3.context() == glw3->context());
+    QVERIFY(guard3.id() == 5);
+
+    // Re-check the share list for the second context (should be empty now).
+    list = shareReg->shares(glw2->context());
+    QCOMPARE(list.size(), 0);
+
+    // Clean up and check that the resources are properly deleted.
+    delete glw2;
+    QCOMPARE(tst_QGLResource::deletions, 1);
+    delete glw3;
+    QCOMPARE(tst_QGLResource::deletions, 2);
+
+    // Guards should now be null and the id zero.
+    QVERIFY(guard.context() == 0);
+    QVERIFY(guard.id() == 0);
+    QVERIFY(guard3.context() == 0);
+    QVERIFY(guard3.id() == 0);
+#endif
+}
+
+QTEST_MAIN(tst_QGL)
+#include "tst_qgl.moc"