<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (<EMAIL>)
**
** 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 <EMAIL>.
**
**
**
**
**
**
**
**
** $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>
#include <QtGui/private/qpixmapdata_p.h>
#include <QtGui/private/qimage_p.h>
#include <QtGui/private/qimagepixmapcleanuphooks_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 glWidgetWithAlpha();
    void glWidgetRendering();
    void glFBOSimpleRendering();
    void glFBORendering();
    void multipleFBOInterleavedRendering();
    void glFBOUseInGLWidget();
    void glPBufferRendering();
    void glWidgetReparent();
    void glWidgetRenderPixmap();
    void colormap();
    void fboFormat();
    void testDontCrashOnDanglingResources();
    void replaceClipping();
    void clipTest();
    void destroyFBOAfterContext();
    void shareRegister();
    void qglContextDefaultBindTexture();
    void textureCleanup();
};

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); }
};

static int appDefaultDepth()
{
    static int depth = 0;
    if (depth == 0) {
        QPixmap pm(1, 1);
        depth = pm.depth();
    }
    return depth;
}

// 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)
    QCOMPARE(false, obj1.sampleBuffers());
    QVERIFY(!obj1.testOption(QGL::SampleBuffers));
    QVERIFY(obj1.testOption(QGL::NoSampleBuffers));

    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
}

static bool fuzzyComparePixels(const QRgb testPixel, const QRgb refPixel, const char* file, int line, int x = -1, int y = -1)
{
    static int maxFuzz = 1;
    static bool maxFuzzSet = false;

    // On 16 bpp systems, we need to allow for more fuzz:
    if (!maxFuzzSet) {
        maxFuzzSet = true;
        if (appDefaultDepth() < 24)
            maxFuzz = 32;
    }

    int redFuzz = qAbs(qRed(testPixel) - qRed(refPixel));
    int greenFuzz = qAbs(qGreen(testPixel) - qGreen(refPixel));
    int blueFuzz = qAbs(qBlue(testPixel) - qBlue(refPixel));
    int alphaFuzz = qAbs(qAlpha(testPixel) - qAlpha(refPixel));

    if (refPixel != 0 && testPixel == 0) {
        QString msg;
        if (x >= 0) {
            msg = QString("Test pixel [%1, %2] is null (black) when it should be (%3,%4,%5,%6)")
                            .arg(x).arg(y)
                            .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        } else {
            msg = QString("Test pixel is null (black) when it should be (%2,%3,%4,%5)")
                            .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        }

        QTest::qFail(msg.toLatin1(), file, line);
        return false;
    }

    if (redFuzz > maxFuzz || greenFuzz > maxFuzz || blueFuzz > maxFuzz || alphaFuzz > maxFuzz) {
        QString msg;

        if (x >= 0)
            msg = QString("Pixel [%1,%2]: ").arg(x).arg(y);
        else
            msg = QString("Pixel ");

        msg += QString("Max fuzz (%1) exceeded: (%2,%3,%4,%5) vs (%6,%7,%8,%9)")
                      .arg(maxFuzz)
                      .arg(qRed(testPixel)).arg(qGreen(testPixel)).arg(qBlue(testPixel)).arg(qAlpha(testPixel))
                      .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        QTest::qFail(msg.toLatin1(), file, line);
        return false;
    }
    return true;
}

static void fuzzyCompareImages(const QImage &testImage, const QImage &referenceImage, const char* file, int line)
{
    QCOMPARE(testImage.width(), referenceImage.width());
    QCOMPARE(testImage.height(), referenceImage.height());

    for (int y = 0; y < testImage.height(); y++) {
        for (int x = 0; x < testImage.width(); x++) {
            if (!fuzzyComparePixels(testImage.pixel(x, y), referenceImage.pixel(x, y), file, line, x, y)) {
                // Might as well save the images for easier debugging:
                referenceImage.save("referenceImage.png");
                testImage.save("testImage.png");
                return;
            }
        }
    }
}

#define QFUZZY_COMPARE_IMAGES(A,B) \
            fuzzyCompareImages(A, B, __FILE__, __LINE__)

#define QFUZZY_COMPARE_PIXELS(A,B) \
            fuzzyComparePixels(A, B, __FILE__, __LINE__)

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);
#ifdef Q_WS_QWS
    view.setWindowFlags(Qt::FramelessWindowHint);
#endif
    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();

    QFUZZY_COMPARE_IMAGES(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();

    QFUZZY_COMPARE_IMAGES(fb, reference);
}

void tst_QGL::glWidgetWithAlpha()
{
    QGLWidget* w = new QGLWidget(QGLFormat(QGL::AlphaChannel));
    w->show();
#ifdef Q_WS_X11
    qt_x11_wait_for_window_manager(w);
#endif

    delete w;
}

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(-1, -1, width()+2, height()+2, Qt::red);

        // No p.end() or swap buffers, should be done automatically
    }

};

void tst_QGL::glWidgetRendering()
{
    GLWidget w;
#ifdef Q_WS_QWS
    w.setWindowFlags(Qt::FramelessWindowHint);
#endif
    w.setGeometry(100, 100, 200, 200);
    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);

    QFUZZY_COMPARE_IMAGES(fb, reference);
}

void tst_QGL::glFBOSimpleRendering()
{
    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::NoAttachment);

    // Don't complicate things by using NPOT:
    QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);

    fbo->bind();

    glClearColor(1.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFinish();

    QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
    QImage reference(fb.size(), QImage::Format_RGB32);
    reference.fill(0xffff0000);

    QFUZZY_COMPARE_IMAGES(fb, reference);

    delete fbo;
}

// 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:
    QFUZZY_COMPARE_PIXELS(fb.pixel(39, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(89, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(64, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(64, 89), QColor(Qt::blue).rgb());

    QFUZZY_COMPARE_PIXELS(fb.pixel(167, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(217, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(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:
    QFUZZY_COMPARE_PIXELS(fb1.pixel(39, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(89, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 89), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(167, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(217, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(192, 64), QColor(Qt::green).rgb());

    QFUZZY_COMPARE_PIXELS(fb2.pixel(39, 64), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(89, 64), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 89), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(167, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(217, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(192, 64), QColor(Qt::blue).rgb());

    QFUZZY_COMPARE_PIXELS(fb3.pixel(39, 64), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(89, 64), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 89), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(167, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(217, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(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(-1, -1, 130, 130, Qt::red);
        fboPainter.end();
        fboImage = fbo->toImage();

        widgetPainter.fillRect(-1, -1, width()+2, width()+2, Qt::blue);

        delete fbo;
    }

};

void tst_QGL::glFBOUseInGLWidget()
{
    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);

    FBOUseInGLWidget w;
#ifdef Q_WS_QWS
    w.setWindowFlags(Qt::FramelessWindowHint);
#endif
    w.resize(128, 128);
    w.show();

#ifdef Q_WS_X11
    qt_x11_wait_for_window_manager(&w);<commit_msg>Skip complex FBO tests if combined depth-stencil isn't supported<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (<EMAIL>)
**
** 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 <EMAIL>.
**
**
**
**
**
**
**
**
** $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>
#include <QtGui/private/qpixmapdata_p.h>
#include <QtGui/private/qimage_p.h>
#include <QtGui/private/qimagepixmapcleanuphooks_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 glWidgetWithAlpha();
    void glWidgetRendering();
    void glFBOSimpleRendering();
    void glFBORendering();
    void multipleFBOInterleavedRendering();
    void glFBOUseInGLWidget();
    void glPBufferRendering();
    void glWidgetReparent();
    void glWidgetRenderPixmap();
    void colormap();
    void fboFormat();
    void testDontCrashOnDanglingResources();
    void replaceClipping();
    void clipTest();
    void destroyFBOAfterContext();
    void shareRegister();
    void qglContextDefaultBindTexture();
    void textureCleanup();
};

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); }
};

static int appDefaultDepth()
{
    static int depth = 0;
    if (depth == 0) {
        QPixmap pm(1, 1);
        depth = pm.depth();
    }
    return depth;
}

// 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)
    QCOMPARE(false, obj1.sampleBuffers());
    QVERIFY(!obj1.testOption(QGL::SampleBuffers));
    QVERIFY(obj1.testOption(QGL::NoSampleBuffers));

    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
}

static bool fuzzyComparePixels(const QRgb testPixel, const QRgb refPixel, const char* file, int line, int x = -1, int y = -1)
{
    static int maxFuzz = 1;
    static bool maxFuzzSet = false;

    // On 16 bpp systems, we need to allow for more fuzz:
    if (!maxFuzzSet) {
        maxFuzzSet = true;
        if (appDefaultDepth() < 24)
            maxFuzz = 32;
    }

    int redFuzz = qAbs(qRed(testPixel) - qRed(refPixel));
    int greenFuzz = qAbs(qGreen(testPixel) - qGreen(refPixel));
    int blueFuzz = qAbs(qBlue(testPixel) - qBlue(refPixel));
    int alphaFuzz = qAbs(qAlpha(testPixel) - qAlpha(refPixel));

    if (refPixel != 0 && testPixel == 0) {
        QString msg;
        if (x >= 0) {
            msg = QString("Test pixel [%1, %2] is null (black) when it should be (%3,%4,%5,%6)")
                            .arg(x).arg(y)
                            .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        } else {
            msg = QString("Test pixel is null (black) when it should be (%2,%3,%4,%5)")
                            .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        }

        QTest::qFail(msg.toLatin1(), file, line);
        return false;
    }

    if (redFuzz > maxFuzz || greenFuzz > maxFuzz || blueFuzz > maxFuzz || alphaFuzz > maxFuzz) {
        QString msg;

        if (x >= 0)
            msg = QString("Pixel [%1,%2]: ").arg(x).arg(y);
        else
            msg = QString("Pixel ");

        msg += QString("Max fuzz (%1) exceeded: (%2,%3,%4,%5) vs (%6,%7,%8,%9)")
                      .arg(maxFuzz)
                      .arg(qRed(testPixel)).arg(qGreen(testPixel)).arg(qBlue(testPixel)).arg(qAlpha(testPixel))
                      .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
        QTest::qFail(msg.toLatin1(), file, line);
        return false;
    }
    return true;
}

static void fuzzyCompareImages(const QImage &testImage, const QImage &referenceImage, const char* file, int line)
{
    QCOMPARE(testImage.width(), referenceImage.width());
    QCOMPARE(testImage.height(), referenceImage.height());

    for (int y = 0; y < testImage.height(); y++) {
        for (int x = 0; x < testImage.width(); x++) {
            if (!fuzzyComparePixels(testImage.pixel(x, y), referenceImage.pixel(x, y), file, line, x, y)) {
                // Might as well save the images for easier debugging:
                referenceImage.save("referenceImage.png");
                testImage.save("testImage.png");
                return;
            }
        }
    }
}

#define QFUZZY_COMPARE_IMAGES(A,B) \
            fuzzyCompareImages(A, B, __FILE__, __LINE__)

#define QFUZZY_COMPARE_PIXELS(A,B) \
            fuzzyComparePixels(A, B, __FILE__, __LINE__)

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);
#ifdef Q_WS_QWS
    view.setWindowFlags(Qt::FramelessWindowHint);
#endif
    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();

    QFUZZY_COMPARE_IMAGES(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();

    QFUZZY_COMPARE_IMAGES(fb, reference);
}

void tst_QGL::glWidgetWithAlpha()
{
    QGLWidget* w = new QGLWidget(QGLFormat(QGL::AlphaChannel));
    w->show();
#ifdef Q_WS_X11
    qt_x11_wait_for_window_manager(w);
#endif

    delete w;
}

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(-1, -1, width()+2, height()+2, Qt::red);

        // No p.end() or swap buffers, should be done automatically
    }

};

void tst_QGL::glWidgetRendering()
{
    GLWidget w;
#ifdef Q_WS_QWS
    w.setWindowFlags(Qt::FramelessWindowHint);
#endif
    w.setGeometry(100, 100, 200, 200);
    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);

    QFUZZY_COMPARE_IMAGES(fb, reference);
}

void tst_QGL::glFBOSimpleRendering()
{
    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::NoAttachment);

    // Don't complicate things by using NPOT:
    QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);

    fbo->bind();

    glClearColor(1.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFinish();

    QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
    QImage reference(fb.size(), QImage::Format_RGB32);
    reference.fill(0xffff0000);

    QFUZZY_COMPARE_IMAGES(fb, reference);

    delete fbo;
}

// 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);

    if (fbo->attachment() != QGLFramebufferObject::CombinedDepthStencil) {
        delete fbo;
        QSKIP("FBOs missing combined depth~stencil support", SkipSingle);
    }

    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:
    QFUZZY_COMPARE_PIXELS(fb.pixel(39, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(89, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(64, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(64, 89), QColor(Qt::blue).rgb());

    QFUZZY_COMPARE_PIXELS(fb.pixel(167, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb.pixel(217, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(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);

    if ( (fbo1->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
         (fbo2->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
         (fbo3->attachment() != QGLFramebufferObject::CombinedDepthStencil)    )
    {
        delete fbo1;
        delete fbo2;
        delete fbo3;
        QSKIP("FBOs missing combined depth~stencil support", SkipSingle);
    }

    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:
    QFUZZY_COMPARE_PIXELS(fb1.pixel(39, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(89, 64), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 89), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(167, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(217, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb1.pixel(192, 64), QColor(Qt::green).rgb());

    QFUZZY_COMPARE_PIXELS(fb2.pixel(39, 64), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(89, 64), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 39), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 89), QColor(Qt::red).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(167, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(217, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb2.pixel(192, 64), QColor(Qt::blue).rgb());

    QFUZZY_COMPARE_PIXELS(fb3.pixel(39, 64), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(89, 64), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 39), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 89), QColor(Qt::green).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(167, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(fb3.pixel(217, 39), QColor(Qt::blue).rgb());
    QFUZZY_COMPARE_PIXELS(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::NoAttachment);
        QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat);

        QPainter fboPainter;
        fboPainterBeginOk = fboPainter.begin(fbo);
        fboPainter.fillRect(-1, -1, 130, 130, Qt::red);
        fboPainter.end();
        fboImage = fbo->toImage();

        widgetPainter.fillRect(-1, -1, width()+2, width()+2, Qt::blue);

        delete fbo;
    }

};

void tst_QGL::glFBOUseInGLWidget()
{
    if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
        QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle);

    FBOUseInGLWidget w;
#ifdef Q_WS_QWS
    w.setWindowFlags(Qt::FramelessWindowHint);
#endif
    w.resize(128, 128);
    w.show();

#ifdef Q_WS_X11
    qt_x11_wait_for_window_manager(&w);
{'fraction_non_alphanumeric': 0.13661489865754145, 'fraction_numerical': 0.029349828902342723, 'mean_word_length': 4.37758773223238, 'pattern_counts': {'":': 0, '<': 97, '<?xml version=': 0, '>': 127, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5739822', 'n_tokens_mistral': 32669, 'n_tokens_neox': 31022, 'n_words': 5541}