From 0bfa24106d1465dccabcf7ad38c9cffdc2229f29 Mon Sep 17 00:00:00 2001 From: Jo Asplin Date: Thu, 8 Sep 2011 15:12:01 +0200 Subject: Moved autotests in category 'opengl' into new directory structure Task-number: QTBUG-21356 Change-Id: I496680aa670af3409e50e1c254ef2c557b414d33 Reviewed-on: http://codereview.qt-project.org/4452 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- tests/auto/auto.pro | 2 +- tests/auto/opengl.pro | 7 - tests/auto/opengl/opengl.pro | 7 + tests/auto/opengl/qgl/.gitignore | 1 + tests/auto/opengl/qgl/qgl.pro | 15 + tests/auto/opengl/qgl/qgl.qrc | 5 + tests/auto/opengl/qgl/tst_qgl.cpp | 2400 ++++++++++++++++++++ tests/auto/opengl/qglbuffer/qglbuffer.pro | 11 + tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp | 261 +++ tests/auto/opengl/qglfunctions/qglfunctions.pro | 7 + .../auto/opengl/qglfunctions/tst_qglfunctions.cpp | 244 ++ tests/auto/opengl/qglthreads/qglthreads.pro | 14 + tests/auto/opengl/qglthreads/tst_qglthreads.cpp | 758 +++++++ tests/auto/opengl/qglthreads/tst_qglthreads.h | 65 + tests/auto/qgl/.gitignore | 1 - tests/auto/qgl/qgl.pro | 15 - tests/auto/qgl/qgl.qrc | 5 - tests/auto/qgl/tst_qgl.cpp | 2400 -------------------- tests/auto/qglbuffer/qglbuffer.pro | 11 - tests/auto/qglbuffer/tst_qglbuffer.cpp | 261 --- tests/auto/qglfunctions/qglfunctions.pro | 7 - tests/auto/qglfunctions/tst_qglfunctions.cpp | 244 -- tests/auto/qglthreads/qglthreads.pro | 14 - tests/auto/qglthreads/tst_qglthreads.cpp | 758 ------- tests/auto/qglthreads/tst_qglthreads.h | 65 - 25 files changed, 3789 insertions(+), 3789 deletions(-) delete mode 100644 tests/auto/opengl.pro create mode 100644 tests/auto/opengl/opengl.pro create mode 100644 tests/auto/opengl/qgl/.gitignore create mode 100644 tests/auto/opengl/qgl/qgl.pro create mode 100644 tests/auto/opengl/qgl/qgl.qrc create mode 100644 tests/auto/opengl/qgl/tst_qgl.cpp create mode 100644 tests/auto/opengl/qglbuffer/qglbuffer.pro create mode 100644 tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp create mode 100644 tests/auto/opengl/qglfunctions/qglfunctions.pro create mode 100644 tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp create mode 100644 tests/auto/opengl/qglthreads/qglthreads.pro create mode 100644 tests/auto/opengl/qglthreads/tst_qglthreads.cpp create mode 100644 tests/auto/opengl/qglthreads/tst_qglthreads.h delete mode 100644 tests/auto/qgl/.gitignore delete mode 100644 tests/auto/qgl/qgl.pro delete mode 100644 tests/auto/qgl/qgl.qrc delete mode 100644 tests/auto/qgl/tst_qgl.cpp delete mode 100644 tests/auto/qglbuffer/qglbuffer.pro delete mode 100644 tests/auto/qglbuffer/tst_qglbuffer.cpp delete mode 100644 tests/auto/qglfunctions/qglfunctions.pro delete mode 100644 tests/auto/qglfunctions/tst_qglfunctions.cpp delete mode 100644 tests/auto/qglthreads/qglthreads.pro delete mode 100644 tests/auto/qglthreads/tst_qglthreads.cpp delete mode 100644 tests/auto/qglthreads/tst_qglthreads.h (limited to 'tests/auto') diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index c2f58835a9..c16f00ff8b 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -9,6 +9,6 @@ SUBDIRS += \ other !cross_compile: SUBDIRS += host.pro -contains(QT_CONFIG, opengl): SUBDIRS += opengl.pro +contains(QT_CONFIG, opengl): SUBDIRS += opengl unix:!embedded:contains(QT_CONFIG, dbus): SUBDIRS += dbus contains(QT_CONFIG, v8): SUBDIRS += v8.pro diff --git a/tests/auto/opengl.pro b/tests/auto/opengl.pro deleted file mode 100644 index 6c8e4ca96b..0000000000 --- a/tests/auto/opengl.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS=\ - qgl \ - qglthreads \ - qglbuffer \ - qglfunctions \ - diff --git a/tests/auto/opengl/opengl.pro b/tests/auto/opengl/opengl.pro new file mode 100644 index 0000000000..6c8e4ca96b --- /dev/null +++ b/tests/auto/opengl/opengl.pro @@ -0,0 +1,7 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qgl \ + qglthreads \ + qglbuffer \ + qglfunctions \ + diff --git a/tests/auto/opengl/qgl/.gitignore b/tests/auto/opengl/qgl/.gitignore new file mode 100644 index 0000000000..bb6e921035 --- /dev/null +++ b/tests/auto/opengl/qgl/.gitignore @@ -0,0 +1 @@ +tst_qgl diff --git a/tests/auto/opengl/qgl/qgl.pro b/tests/auto/opengl/qgl/qgl.pro new file mode 100644 index 0000000000..c5e26451ed --- /dev/null +++ b/tests/auto/opengl/qgl/qgl.pro @@ -0,0 +1,15 @@ +############################################################ +# Project file for autotest for file qgl.h +############################################################ + +load(qttest_p4) +requires(contains(QT_CONFIG,opengl)) +QT += widgets widgets-private opengl-private gui-private core-private + +contains(QT_CONFIG,egl):DEFINES += QGL_EGL +win32:!wince*: DEFINES += QT_NO_EGL + +SOURCES += tst_qgl.cpp +RESOURCES = qgl.qrc + +CONFIG+=insignificant_test diff --git a/tests/auto/opengl/qgl/qgl.qrc b/tests/auto/opengl/qgl/qgl.qrc new file mode 100644 index 0000000000..70f425c1b9 --- /dev/null +++ b/tests/auto/opengl/qgl/qgl.qrc @@ -0,0 +1,5 @@ + + + ../../gui/image/qpixmap/images/designer.png + + diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp new file mode 100644 index 0000000000..e1c3462560 --- /dev/null +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -0,0 +1,2400 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef QT_BUILD_INTERNAL +#include +#include +#include +#include +#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(); + void threadImages(); + void nullRectCrash(); +}; + +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(1); + QCOMPARE(true, obj1.alpha()); // setAlphaBufferSize() enables alpha. + QCOMPARE(1, obj1.alphaBufferSize()); + QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -2147483648"); + obj1.setAlphaBufferSize(TEST_INT_MIN); + QCOMPARE(1, 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(1); + QCOMPARE(1, obj1.stencilBufferSize()); + QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -2147483648"); + obj1.setStencilBufferSize(TEST_INT_MIN); + QCOMPARE(1, 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) + obj1.setAccumBufferSize(0); + 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()); + + // int QGLFormat::major/minorVersion() + // void QGLFormat::setVersion(int, int) + QCOMPARE(obj1.majorVersion(), 1); + QCOMPARE(obj1.minorVersion(), 0); + obj1.setVersion(3, 2); + QCOMPARE(obj1.majorVersion(), 3); + QCOMPARE(obj1.minorVersion(), 2); + QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 0.1"); + obj1.setVersion(0, 1); + QCOMPARE(obj1.majorVersion(), 3); + QCOMPARE(obj1.minorVersion(), 2); + QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 3.-1"); + obj1.setVersion(3, -1); + QCOMPARE(obj1.majorVersion(), 3); + QCOMPARE(obj1.minorVersion(), 2); + obj1.setVersion(TEST_INT_MAX, TEST_INT_MAX - 1); + QCOMPARE(obj1.majorVersion(), TEST_INT_MAX); + QCOMPARE(obj1.minorVersion(), TEST_INT_MAX - 1); + + + // 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)); + + format1.setVersion(3, 2); + QVERIFY(!(format1 == format2)); + QVERIFY(format1 != format2); + format2.setVersion(3, 2); + QVERIFY(format1 == format2); + QVERIFY(!(format1 != format2)); + + format1.setProfile(QGLFormat::CoreProfile); + QVERIFY(!(format1 == format2)); + QVERIFY(format1 != format2); + format2.setProfile(QGLFormat::CoreProfile); + QVERIFY(format1 == format2); + QVERIFY(!(format1 != format2)); + + format1.setOption(QGL::NoDeprecatedFunctions); + QVERIFY(!(format1 == format2)); + QVERIFY(format1 != format2); + format2.setOption(QGL::NoDeprecatedFunctions); + 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_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); + view.setBackgroundBrush(Qt::white); +#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("doubleBufferedContext"); + QTest::addColumn("autoFillBackground"); + QTest::addColumn("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(); + + 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); + + 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; +} + + +void qt_opengl_draw_test_pattern(QPainter* painter, int width, int height) +{ + 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(); + + painter->setTransform(QTransform()); // reset xform + painter->fillRect(-1, -1, width+2, height+2, Qt::red); // Background + painter->translate(14, 14); + painter->fillPath(intersectingPath, Qt::blue); // Test stencil buffer works + painter->translate(128, 0); + painter->setClipPath(trianglePath); // Test depth buffer works + painter->setTransform(QTransform()); // reset xform ready for fill + painter->fillRect(-1, -1, width+2, height+2, Qt::green); +} + +void qt_opengl_check_test_pattern(const QImage& img) +{ + // 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(img.pixel(39, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(img.pixel(89, 64), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(img.pixel(64, 39), QColor(Qt::blue).rgb()); + QFUZZY_COMPARE_PIXELS(img.pixel(64, 89), QColor(Qt::blue).rgb()); + + QFUZZY_COMPARE_PIXELS(img.pixel(167, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(img.pixel(217, 39), QColor(Qt::red).rgb()); + QFUZZY_COMPARE_PIXELS(img.pixel(192, 64), QColor(Qt::green).rgb()); +} + +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(); + + qt_opengl_draw_test_pattern(&p, width(), height()); + + // 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.resize(256, 128); + 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); + qt_opengl_check_test_pattern(fb); +} + +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); + + QGLFramebufferObject *fbo = new QGLFramebufferObject(200, 100, 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); + + qt_opengl_draw_test_pattern(&fboPainter, fbo->width(), fbo->height()); + + fboPainter.end(); + + QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32); + delete fbo; + + qt_opengl_check_test_pattern(fb); +} + + +// 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(100, 100, 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(100, 100); + 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); + QFUZZY_COMPARE_IMAGES(widgetFB, widgetReference); + + QImage fboReference(w.fboImage.size(), w.fboImage.format()); + fboReference.fill(0xffff0000); + QFUZZY_COMPARE_IMAGES(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); + +#if defined(QGL_EGL) && !defined(Q_WS_X11) + QSKIP("renderPixmap() not yet supported under EGL on your platform", SkipAll); +#endif + + QFUZZY_COMPARE_IMAGES(fb, reference); +} + +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; +#ifdef Q_WS_QWS + glw.setWindowFlags(Qt::FramelessWindowHint); +#endif + 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); + + // Sample pixels in a grid pattern which avoids false failures due to + // off-by-one pixel errors on some buggy GL implementations + for (int x = 25; x < reference.width(); x += 50) { + for (int y = 25; y < reference.width(); y += 50) { + QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); + } + } +} + +class ClipTestGLWidget : public QGLWidget +{ +public: + void paint(QPainter *painter) + { + painter->fillRect(-1, -1, width()+2, height()+2, 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->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(); + } + +protected: + void paintEvent(QPaintEvent*) + { + QPainter painter(this); + paint(&painter); + } +}; + +void tst_QGL::clipTest() +{ + ClipTestGLWidget glw; +#ifdef Q_WS_QWS + glw.setWindowFlags(Qt::FramelessWindowHint); +#endif + 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); + + // Sample pixels in a grid pattern which avoids false failures due to + // off-by-one pixel errors on some buggy GL implementations + for (int x = 2; x < reference.width(); x += 5) { + for (int y = 2; y < reference.height(); y += 5) { + QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); + } + } +} + +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: + tst_QGLResource(const QGLContext * = 0) {} + ~tst_QGLResource() { ++deletions; } + + static int deletions; +}; + +int tst_QGLResource::deletions = 0; + +#ifdef TODO +Q_GLOBAL_STATIC(QOpenGLContextGroupResource, qt_shared_test) +#endif //TODO +#endif + +void tst_QGL::shareRegister() +{ +#ifdef TODO +#ifdef QT_BUILD_INTERNAL + // Create a context. + QGLWidget *glw1 = new QGLWidget(); + glw1->makeCurrent(); + + // Nothing should be sharing with glw1's context yet. + QVERIFY(!glw1->isSharing()); + + // Create a guard for the first context. + QOpenGLSharedResourceGuard guard(glw1->context()->contextHandle()); + QVERIFY(guard.id() == 0); + guard.setId(3); + QVERIFY(guard.id() == 3); + + // Request a tst_QGLResource object for the first context. + tst_QGLResource *res1 = qt_shared_test()->value(glw1->context()->contextHandle()); + QVERIFY(res1); + QVERIFY(qt_shared_test()->value(glw1->context()->contextHandle()) == res1); + + // Create another context that shares with the first. + QVERIFY(!glw1->isSharing()); + QGLWidget *glw2 = new QGLWidget(0, glw1); + if (!glw2->isSharing()) { + delete glw2; + delete glw1; + QSKIP("Context sharing is not supported", SkipSingle); + } + QVERIFY(glw1->isSharing()); + 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); + + // 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(); + QVERIFY(!glw3->isSharing()); + + // Create a guard on the standalone context. + QGLSharedResourceGuard guard3(glw3->context()); + guard3.setId(5); + + // Request a resource to the third context. + tst_QGLResource *res3 = qt_shared_test()->value(glw3->context()); + QVERIFY(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); + + // 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 second context should no longer register as sharing. + QVERIFY(!glw2->isSharing()); + + // 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); + + // 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 +#endif //TODO +} + +// Tests QGLContext::bindTexture with default options +void tst_QGL::qglContextDefaultBindTexture() +{ +#ifdef QT_BUILD_INTERNAL + QGLWidget w; + w.makeCurrent(); + QGLContext *ctx = const_cast(w.context()); + + QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); + boundImage->fill(0xFFFFFFFF); + QPixmap *boundPixmap = new QPixmap(256, 256); + boundPixmap->fill(Qt::red); + + int startCacheItemCount = QGLTextureCache::instance()->size(); + + GLuint boundImageTextureId = ctx->bindTexture(*boundImage); + GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap); + + // Make sure the image & pixmap have been added to the cache: + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Make sure the image & pixmap have the is_cached flag set: + QVERIFY(QImagePixmapCleanupHooks::isImageCached(*boundImage)); + QVERIFY(QImagePixmapCleanupHooks::isPixmapCached(*boundPixmap)); + + // Make sure the texture IDs returned are valid: + QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE); + QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE); + + // Make sure the textures are still valid after we delete the image/pixmap: + // Also check that although the textures are left intact, the cache entries are removed: + delete boundImage; + boundImage = 0; + QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + delete boundPixmap; + boundPixmap = 0; + QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + // Finally, make sure QGLContext::deleteTexture deletes the texture IDs: + ctx->deleteTexture(boundImageTextureId); + ctx->deleteTexture(boundPixmapTextureId); + QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_FALSE); + QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_FALSE); +#endif +} + +void tst_QGL::textureCleanup() +{ +#ifdef QT_BUILD_INTERNAL + QGLWidget w; + w.resize(200,200); + w.show(); + w.makeCurrent(); + + // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache + // when the pixmap cache is cleared + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QPixmap boundPixmap(":designer.png"); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Check that the texture doesn't get removed from the cache when the pixmap is cleared + // as it should still be in the cache: + boundPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + QPixmapCache::clear(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache + // when they are explicitly removed from the pixmap cache + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QPixmap boundPixmap(128, 128); + QString cacheKey = QString::fromLatin1("myPixmap"); + QPixmapCache::insert(cacheKey, boundPixmap); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Check that the texture doesn't get removed from the cache when the pixmap is cleared + // as it should still be in the cache: + boundPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Finally, we check that the texture cache entry is removed when we remove the + // pixmap cache entry, which should hold the last reference: + QPixmapCache::remove(cacheKey); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are deleted + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); + boundImage->fill(0xFFFFFFFF); + QPixmap *boundPixmap = new QPixmap(256, 256); + boundPixmap->fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, *boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, *boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + delete boundImage; + boundImage = 0; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + delete boundPixmap; + boundPixmap = 0; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are assigned to + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + boundImage = QImage(64, 64, QImage::Format_RGB32); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + boundPixmap = QPixmap(64, 64); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are modified (detached) + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + boundImage.fill(0x00000000); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + boundPixmap.fill(Qt::blue); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made + QImage copyOfImage; + QPixmap copyOfPixmap; + int startCacheItemCount = QGLTextureCache::instance()->size(); + { + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + copyOfImage = boundImage; + copyOfPixmap = boundPixmap; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + } // boundImage & boundPixmap would have been deleted when they went out of scope + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + copyOfImage = QImage(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + copyOfPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); +#endif +} + +namespace ThreadImages { + +class Producer : public QObject +{ + Q_OBJECT +public: + Producer() + { + startTimer(20); + + QThread *thread = new QThread; + thread->start(); + + connect(this, SIGNAL(destroyed()), thread, SLOT(quit())); + + moveToThread(thread); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + } + +signals: + void imageReady(const QImage &image); + +protected: + void timerEvent(QTimerEvent *) + { + QImage image(256, 256, QImage::Format_RGB32); + QLinearGradient g(0, 0, 0, 256); + g.setColorAt(0, QColor(255, 180, 180)); + g.setColorAt(1, Qt::white); + g.setSpread(QGradient::ReflectSpread); + + QBrush brush(g); + brush.setTransform(QTransform::fromTranslate(0, delta)); + delta += 10; + + QPainter p(&image); + p.fillRect(image.rect(), brush); + + if (images.size() > 10) + images.removeFirst(); + + images.append(image); + + emit imageReady(image); + } + +private: + QList images; + int delta; +}; + + +class DisplayWidget : public QGLWidget +{ + Q_OBJECT +public: + DisplayWidget(QWidget *parent) : QGLWidget(parent) {} + void paintEvent(QPaintEvent *) + { + QPainter p(this); + p.drawImage(rect(), m_image); + } + +public slots: + void setImage(const QImage &image) + { + m_image = image; + update(); + } + +private: + QImage m_image; +}; + +class Widget : public QWidget +{ + Q_OBJECT +public: + Widget() + : iterations(0) + , display(0) + , producer(new Producer) + { + startTimer(400); + connect(this, SIGNAL(destroyed()), producer, SLOT(deleteLater())); + } + + int iterations; + +protected: + void timerEvent(QTimerEvent *) + { + ++iterations; + + delete display; + display = new DisplayWidget(this); + connect(producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &))); + + display->setGeometry(rect()); + display->show(); + } + +private: + DisplayWidget *display; + Producer *producer; +}; + +} + +void tst_QGL::threadImages() +{ + ThreadImages::Widget *widget = new ThreadImages::Widget; + widget->show(); + + while (widget->iterations <= 5) { + qApp->processEvents(); + } + + delete widget; +} + +void tst_QGL::nullRectCrash() +{ + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); + + QGLWidget glw; + glw.makeCurrent(); + + QGLFramebufferObjectFormat fboFormat; + fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + + QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat); + + QPainter fboPainter(fbo); + + fboPainter.setPen(QPen(QColor(255, 127, 127, 127), 2)); + fboPainter.setBrush(QColor(127, 255, 127, 127)); + fboPainter.drawRect(QRectF()); + + fboPainter.end(); +} + +class tst_QGLDummy : public QObject +{ +Q_OBJECT + +public: + tst_QGLDummy() {} + +private slots: + void qglSkipTests() { + QSKIP("QGL not supported on this system.", SkipAll); + } +}; + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QTEST_DISABLE_KEYPAD_NAVIGATION \ + QGLWidget glWidget; + if (!glWidget.isValid()) { + tst_QGLDummy tc; + return QTest::qExec(&tc, argc, argv); + } + tst_QGL tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qgl.moc" diff --git a/tests/auto/opengl/qglbuffer/qglbuffer.pro b/tests/auto/opengl/qglbuffer/qglbuffer.pro new file mode 100644 index 0000000000..48bd966797 --- /dev/null +++ b/tests/auto/opengl/qglbuffer/qglbuffer.pro @@ -0,0 +1,11 @@ +############################################################ +# Project file for autotest for file qglbuffer.h +############################################################ + +load(qttest_p4) +requires(contains(QT_CONFIG,opengl)) +QT += opengl widgets + +win32:!wince*: DEFINES += QT_NO_EGL + +SOURCES += tst_qglbuffer.cpp diff --git a/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp b/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp new file mode 100644 index 0000000000..9215b5fedd --- /dev/null +++ b/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +class tst_QGLBuffer : public QObject +{ + Q_OBJECT +public: + tst_QGLBuffer() {} + ~tst_QGLBuffer() {} + +private slots: + void vertexBuffer_data(); + void vertexBuffer(); + void indexBuffer_data(); + void indexBuffer(); + void bufferSharing(); + +private: + void testBuffer(QGLBuffer::Type type); +}; + +void tst_QGLBuffer::vertexBuffer_data() +{ + QTest::addColumn("usagePattern"); + + QTest::newRow("StreamDraw") << int(QGLBuffer::StreamDraw); + QTest::newRow("StaticDraw") << int(QGLBuffer::StaticDraw); + QTest::newRow("DynamicDraw") << int(QGLBuffer::DynamicDraw); +} + +void tst_QGLBuffer::vertexBuffer() +{ + testBuffer(QGLBuffer::VertexBuffer); +} + +void tst_QGLBuffer::indexBuffer_data() +{ + vertexBuffer_data(); +} + +void tst_QGLBuffer::indexBuffer() +{ + testBuffer(QGLBuffer::IndexBuffer); +} + +void tst_QGLBuffer::testBuffer(QGLBuffer::Type type) +{ + QFETCH(int, usagePattern); + + QGLWidget w; + w.makeCurrent(); + + // Create the local object, but not the buffer in the server. + QGLBuffer buffer(type); + QVERIFY(buffer.usagePattern() == QGLBuffer::StaticDraw); + buffer.setUsagePattern(QGLBuffer::UsagePattern(usagePattern)); + + // Check the initial state. + QVERIFY(buffer.type() == type); + QVERIFY(!buffer.isCreated()); + QVERIFY(buffer.bufferId() == 0); + QVERIFY(buffer.usagePattern() == QGLBuffer::UsagePattern(usagePattern)); + QCOMPARE(buffer.size(), -1); + + // Should not be able to bind it yet because it isn't created. + QVERIFY(!buffer.bind()); + + // Create the buffer - if this fails, then assume that the + // GL implementation does not support buffers at all. + if (!buffer.create()) + QSKIP("Buffers are not supported on this platform", SkipAll); + + // Should now have a buffer id. + QVERIFY(buffer.bufferId() != 0); + + // Bind the buffer and upload some data. + QVERIFY(buffer.bind()); + static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + buffer.allocate(data, sizeof(data)); + + // Check the buffer size. + QCOMPARE(buffer.size(), int(sizeof(data))); + + // Map the buffer and read back its contents. + bool haveMap = false; + GLfloat *mapped = reinterpret_cast + (buffer.map(QGLBuffer::ReadOnly)); + if (mapped) { + for (int index = 0; index < 9; ++index) + QCOMPARE(mapped[index], data[index]); + buffer.unmap(); + haveMap = true; + } else { + qWarning("QGLBuffer::map() is not supported on this platform"); + } + + // Read back the buffer contents using read(). + bool haveRead = false; + GLfloat readdata[9]; + if (buffer.read(0, readdata, sizeof(readdata))) { + for (int index = 0; index < 9; ++index) + QCOMPARE(readdata[index], data[index]); + haveRead = true; + } else { + qWarning("QGLBuffer::read() is not supported on this platform"); + } + + // Write some different data to a specific location and check it. + static GLfloat const diffdata[] = {11, 12, 13}; + buffer.write(sizeof(GLfloat) * 3, diffdata, sizeof(diffdata)); + if (haveMap) { + mapped = reinterpret_cast(buffer.map(QGLBuffer::ReadOnly)); + QVERIFY(mapped != 0); + for (int index = 0; index < 9; ++index) { + if (index >= 3 && index <= 5) + QCOMPARE(mapped[index], diffdata[index - 3]); + else + QCOMPARE(mapped[index], data[index]); + } + buffer.unmap(); + } + if (haveRead) { + QVERIFY(buffer.read(0, readdata, sizeof(readdata))); + for (int index = 0; index < 9; ++index) { + if (index >= 3 && index <= 5) + QCOMPARE(readdata[index], diffdata[index - 3]); + else + QCOMPARE(readdata[index], data[index]); + } + } + + // Write to the buffer using the return value from map. + if (haveMap) { + mapped = reinterpret_cast(buffer.map(QGLBuffer::WriteOnly)); + QVERIFY(mapped != 0); + mapped[6] = 14; + buffer.unmap(); + + mapped = reinterpret_cast(buffer.map(QGLBuffer::ReadOnly)); + QVERIFY(mapped != 0); + static GLfloat const diff2data[] = {11, 12, 13, 14}; + for (int index = 0; index < 9; ++index) { + if (index >= 3 && index <= 6) + QCOMPARE(mapped[index], diff2data[index - 3]); + else + QCOMPARE(mapped[index], data[index]); + } + buffer.unmap(); + } + + // Resize the buffer. + buffer.allocate(sizeof(GLfloat) * 20); + QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 20)); + buffer.allocate(0, sizeof(GLfloat) * 32); + QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 32)); + + // Release the buffer. + buffer.release(); +} + +void tst_QGLBuffer::bufferSharing() +{ + QGLWidget *w1 = new QGLWidget(); + w1->makeCurrent(); + + QGLWidget *w2 = new QGLWidget(0, w1); + if (!w2->isSharing()) { + delete w2; + delete w1; + QSKIP("Context sharing is not supported on this platform", SkipSingle); + } + + // Bind the buffer in the first context and write some data to it. + QGLBuffer buffer(QGLBuffer::VertexBuffer); + if (!buffer.create()) + QSKIP("Buffers are not supported on this platform", SkipSingle); + QVERIFY(buffer.isCreated()); + QVERIFY(buffer.bind()); + static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + buffer.allocate(data, sizeof(data)); + QCOMPARE(buffer.size(), int(sizeof(data))); + buffer.release(); + + // Bind the buffer in the second context and read back the data. + w2->makeCurrent(); + QVERIFY(buffer.bind()); + QCOMPARE(buffer.size(), int(sizeof(data))); + GLfloat readdata[9]; + if (buffer.read(0, readdata, sizeof(readdata))) { + for (int index = 0; index < 9; ++index) + QCOMPARE(readdata[index], data[index]); + } + buffer.release(); + + // Delete the first context. + delete w1; + + // Make the second context current again because deleting the first + // one will call doneCurrent() even though it wasn't current! + w2->makeCurrent(); + + // The buffer should still be valid in the second context. + QVERIFY(buffer.bufferId() != 0); + QVERIFY(buffer.isCreated()); + QVERIFY(buffer.bind()); + QCOMPARE(buffer.size(), int(sizeof(data))); + buffer.release(); + + // Delete the second context. + delete w2; + + // The buffer should now be invalid. + QVERIFY(buffer.bufferId() == 0); + QVERIFY(!buffer.isCreated()); +} + +QTEST_MAIN(tst_QGLBuffer) + +#include "tst_qglbuffer.moc" diff --git a/tests/auto/opengl/qglfunctions/qglfunctions.pro b/tests/auto/opengl/qglfunctions/qglfunctions.pro new file mode 100644 index 0000000000..9fe8de2b23 --- /dev/null +++ b/tests/auto/opengl/qglfunctions/qglfunctions.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +requires(contains(QT_CONFIG,opengl)) +QT += opengl widgets + +win32:!wince*: DEFINES += QT_NO_EGL + +SOURCES += tst_qglfunctions.cpp diff --git a/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp b/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp new file mode 100644 index 0000000000..ec87f6f857 --- /dev/null +++ b/tests/auto/opengl/qglfunctions/tst_qglfunctions.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +class tst_QGLFunctions : public QObject +{ + Q_OBJECT +public: + tst_QGLFunctions() {} + ~tst_QGLFunctions() {} + +private slots: + void features(); + void multitexture(); + void blendColor(); + +private: + static bool hasExtension(const char *name); +}; + +bool tst_QGLFunctions::hasExtension(const char *name) +{ + QString extensions = + QString::fromLatin1 + (reinterpret_cast(glGetString(GL_EXTENSIONS))); + return extensions.split(QLatin1Char(' ')).contains + (QString::fromLatin1(name)); +} + +// Check that the reported features are consistent with the platform. +void tst_QGLFunctions::features() +{ + // Before being associated with a context, there should be + // no features enabled. + QGLFunctions funcs; + QVERIFY(!funcs.openGLFeatures()); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Shaders)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Buffers)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Framebuffers)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendEquation)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Multisample)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures)); + + // Make a context current. + QGLWidget glw; + if (!glw.isValid()) + QSKIP("Could not create a GL context", SkipAll); + glw.makeCurrent(); + funcs.initializeGLFunctions(); + + // Validate the features against what we expect for this platform. +#if defined(QT_OPENGL_ES_2) + QGLFunctions::OpenGLFeatures allFeatures = + (QGLFunctions::Multitexture | + QGLFunctions::Shaders | + QGLFunctions::Buffers | + QGLFunctions::Framebuffers | + QGLFunctions::BlendColor | + QGLFunctions::BlendEquation | + QGLFunctions::BlendEquationSeparate | + QGLFunctions::BlendFuncSeparate | + QGLFunctions::BlendSubtract | + QGLFunctions::CompressedTextures | + QGLFunctions::Multisample | + QGLFunctions::StencilSeparate | + QGLFunctions::NPOTTextures); + QVERIFY((funcs.openGLFeatures() & allFeatures) == allFeatures); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Shaders)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Buffers)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendEquation)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multisample)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures)); +#elif defined(QT_OPENGL_ES) + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Buffers)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); + QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multisample)); + + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Shaders)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); + QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); + + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers), + hasExtension("GL_OES_framebuffer_object")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate), + hasExtension("GL_OES_blend_equation_separate")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate), + hasExtension("GL_OES_blend_func_separate")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract), + hasExtension("GL_OES_blend_subtract")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures), + hasExtension("GL_OES_texture_npot")); +#else + // We check for both the extension name and the minimum OpenGL version + // for the feature. This will help us catch situations where a platform + // doesn't list an extension by name but does have the feature by virtue + // of its version number. + QGLFormat::OpenGLVersionFlags versions = QGLFormat::openGLVersionFlags(); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Multitexture), + hasExtension("GL_ARB_multitexture") || + (versions & QGLFormat::OpenGL_Version_1_3) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Shaders), + hasExtension("GL_ARB_shader_objects") || + (versions & QGLFormat::OpenGL_Version_2_0) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Buffers), + (versions & QGLFormat::OpenGL_Version_1_5) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers), + hasExtension("GL_EXT_framebuffer_object") || + hasExtension("GL_ARB_framebuffer_object")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendColor), + hasExtension("GL_EXT_blend_color") || + (versions & QGLFormat::OpenGL_Version_1_2) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquation), + (versions & QGLFormat::OpenGL_Version_1_2) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate), + hasExtension("GL_EXT_blend_equation_separate") || + (versions & QGLFormat::OpenGL_Version_2_0) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate), + hasExtension("GL_EXT_blend_func_separate") || + (versions & QGLFormat::OpenGL_Version_1_4) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract), + hasExtension("GL_EXT_blend_subtract")); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures), + hasExtension("GL_ARB_texture_compression") || + (versions & QGLFormat::OpenGL_Version_1_3) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Multisample), + hasExtension("GL_ARB_multisample") || + (versions & QGLFormat::OpenGL_Version_1_3) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate), + (versions & QGLFormat::OpenGL_Version_2_0) != 0); + QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures), + hasExtension("GL_ARB_texture_non_power_of_two") || + (versions & QGLFormat::OpenGL_Version_2_0) != 0); +#endif +} + +// Verify that the multitexture functions appear to resolve and work. +void tst_QGLFunctions::multitexture() +{ + QGLFunctions funcs; + QGLWidget glw; + if (!glw.isValid()) + QSKIP("Could not create a GL context", SkipAll); + glw.makeCurrent(); + funcs.initializeGLFunctions(); + + if (!funcs.hasOpenGLFeature(QGLFunctions::Multitexture)) + QSKIP("Multitexture functions are not supported", SkipSingle); + + funcs.glActiveTexture(GL_TEXTURE1); + + GLint active = 0; + glGetIntegerv(GL_ACTIVE_TEXTURE, &active); + QVERIFY(active == GL_TEXTURE1); + + funcs.glActiveTexture(GL_TEXTURE0); + + active = 0; + glGetIntegerv(GL_ACTIVE_TEXTURE, &active); + QVERIFY(active == GL_TEXTURE0); +} + +// Verify that the glBlendColor() function appears to resolve and work. +void tst_QGLFunctions::blendColor() +{ + QGLFunctions funcs; + QGLWidget glw; + if (!glw.isValid()) + QSKIP("Could not create a GL context", SkipAll); + glw.makeCurrent(); + funcs.initializeGLFunctions(); + + if (!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)) + QSKIP("glBlendColor() is not supported", SkipSingle); + + funcs.glBlendColor(0.0f, 1.0f, 0.0f, 1.0f); + + GLfloat colors[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + glGetFloatv(GL_BLEND_COLOR, colors); + + QCOMPARE(colors[0], 0.0f); + QCOMPARE(colors[1], 1.0f); + QCOMPARE(colors[2], 0.0f); + QCOMPARE(colors[3], 1.0f); +} + +QTEST_MAIN(tst_QGLFunctions) + +#include "tst_qglfunctions.moc" diff --git a/tests/auto/opengl/qglthreads/qglthreads.pro b/tests/auto/opengl/qglthreads/qglthreads.pro new file mode 100644 index 0000000000..d2fd31411f --- /dev/null +++ b/tests/auto/opengl/qglthreads/qglthreads.pro @@ -0,0 +1,14 @@ +load(qttest_p4) +requires(contains(QT_CONFIG,opengl)) +QT += opengl widgets + +win32:!wince*: DEFINES += QT_NO_EGL + +HEADERS += tst_qglthreads.h +SOURCES += tst_qglthreads.cpp + +x11 { + LIBS += $$QMAKE_LIBS_X11 +} + +CONFIG+=insignificant_test diff --git a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp new file mode 100644 index 0000000000..ee05e406c8 --- /dev/null +++ b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp @@ -0,0 +1,758 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include "tst_qglthreads.h" + +#ifdef Q_OS_SYMBIAN +#define RUNNING_TIME 2000 // save GPU mem by running shorter time. +#else +#define RUNNING_TIME 5000 +#endif + + + + +tst_QGLThreads::tst_QGLThreads(QObject *parent) + : QObject(parent) +{ +} + +/* + + swapInThread + + The purpose of this testcase is to verify that it is possible to do rendering into + a GL context from the GUI thread, then swap the contents in from a background thread. + + The usecase for this is to have the background thread do the waiting for vertical + sync while the GUI thread is idle. + + Currently the locking is handled directly in the paintEvent(). For the actual usecase + in Qt, the locking is done in the windowsurface before starting any drawing while + unlocking is done after all drawing has been done. + */ + + +class SwapThread : public QThread +{ + Q_OBJECT +public: + SwapThread(QGLWidget *widget) + : m_widget(widget) + { + moveToThread(this); + } + + void run() { + QTime time; + time.start(); + while (time.elapsed() < RUNNING_TIME) { + lock(); + wait(); + + m_widget->makeCurrent(); + m_widget->swapBuffers(); + m_widget->doneCurrent(); + unlock(); + } + } + + void lock() { m_mutex.lock(); } + void unlock() { m_mutex.unlock(); } + + void wait() { m_wait_condition.wait(&m_mutex); } + void notify() { m_wait_condition.wakeAll(); } + +private: + QGLWidget *m_widget; + QMutex m_mutex; + QWaitCondition m_wait_condition; +}; + +class ForegroundWidget : public QGLWidget +{ +public: + ForegroundWidget(const QGLFormat &format) + : QGLWidget(format), m_thread(0) + { + setAutoBufferSwap(false); + } + + void paintEvent(QPaintEvent *) + { + m_thread->lock(); + makeCurrent(); + QPainter p(this); + p.fillRect(rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); + p.setPen(Qt::red); + p.setFont(QFont("SansSerif", 24)); + p.drawText(rect(), Qt::AlignCenter, "This is an autotest"); + p.end(); + doneCurrent(); + m_thread->notify(); + m_thread->unlock(); + + update(); + } + + void setThread(SwapThread *thread) { + m_thread = thread; + } + + SwapThread *m_thread; +}; + +void tst_QGLThreads::swapInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); +#endif + + QGLFormat format; + format.setSwapInterval(1); + ForegroundWidget widget(format); + SwapThread thread(&widget); + widget.setThread(&thread); + widget.show(); + + QTest::qWaitForWindowShown(&widget); + thread.start(); + + while (thread.isRunning()) { + qApp->processEvents(); + } + + widget.hide(); + + QVERIFY(true); +} + + + + + + + +/* + textureUploadInThread + + The purpose of this testcase is to verify that doing texture uploads in a background + thread is possible and that it works. + */ + +class CreateAndUploadThread : public QThread +{ + Q_OBJECT +public: + CreateAndUploadThread(QGLWidget *shareWidget) + { + m_gl = new QGLWidget(0, shareWidget); + moveToThread(this); + } + + ~CreateAndUploadThread() + { + delete m_gl; + } + + void run() { + m_gl->makeCurrent(); + QTime time; + time.start(); + while (time.elapsed() < RUNNING_TIME) { + int width = 400; + int height = 300; +#ifdef Q_OS_SYMBIAN + // GPU mem is very scarce resource on Symbian currently. + // That's why we create only small textures. + width = 50; + height = 20; +#endif + QImage image(width, height, QImage::Format_RGB32); + QPainter p(&image); + p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); + p.setPen(Qt::red); + p.setFont(QFont("SansSerif", 24)); + p.drawText(image.rect(), Qt::AlignCenter, "This is an autotest"); + p.end(); + m_gl->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); + + createdAndUploaded(image); + } + } + +signals: + void createdAndUploaded(const QImage &image); + +private: + QGLWidget *m_gl; +}; + +class TextureDisplay : public QGLWidget +{ + Q_OBJECT +public: + void paintEvent(QPaintEvent *) { + QPainter p(this); + for (int i=0; i 100) { + m_images.takeFirst(); + m_positions.takeFirst(); + } + } + +private: + QList m_images; + QList m_positions; +}; + +void tst_QGLThreads::textureUploadInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); +#endif + + TextureDisplay display; + CreateAndUploadThread thread(&display); + + connect(&thread, SIGNAL(createdAndUploaded(QImage)), &display, SLOT(receiveImage(QImage))); + + display.show(); + QTest::qWaitForWindowShown(&display); + + thread.start(); + + while (thread.isRunning()) { + qApp->processEvents(); + } + + QVERIFY(true); +} + + + + + + +/* + renderInThread + + This test sets up a scene and renders it in a different thread. + For simplicity, the scene is simply a bunch of rectangles, but + if that works, we're in good shape.. + */ + +static inline float qrandom() { return (rand() % 100) / 100.f; } + +void renderAScene(int w, int h) +{ +#ifdef QT_OPENGL_ES_2 + QGLShaderProgram program; + program.addShaderFromSourceCode(QGLShader::Vertex, "attribute highp vec2 pos; void main() { gl_Position = vec4(pos.xy, 1.0, 1.0); }"); + program.addShaderFromSourceCode(QGLShader::Fragment, "uniform lowp vec4 color; void main() { gl_FragColor = color; }"); + program.bindAttributeLocation("pos", 0); + program.bind(); + int colorId = program.uniformLocation("color"); + + glEnableVertexAttribArray(0); + + for (int i=0; i<1000; ++i) { + GLfloat pos[] = { + (rand() % 100) / 100., + (rand() % 100) / 100., + (rand() % 100) / 100., + (rand() % 100) / 100., + (rand() % 100) / 100., + (rand() % 100) / 100. + }; + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, pos); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); + } +#else + glViewport(0, 0, w, h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(0, w, h, 0, 1, 100); + glTranslated(0, 0, -1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + for (int i=0;i<1000; ++i) { + glBegin(GL_TRIANGLES); + glColor3f(qrandom(), qrandom(), qrandom()); + glVertex2f(qrandom() * w, qrandom() * h); + glColor3f(qrandom(), qrandom(), qrandom()); + glVertex2f(qrandom() * w, qrandom() * h); + glColor3f(qrandom(), qrandom(), qrandom()); + glVertex2f(qrandom() * w, qrandom() * h); + glEnd(); + } +#endif +} + +class ThreadSafeGLWidget : public QGLWidget +{ +public: + ThreadSafeGLWidget(QWidget *parent = 0) : QGLWidget(parent) {} + void paintEvent(QPaintEvent *) + { + // ignored as we're anyway swapping as fast as we can + }; + + void resizeEvent(QResizeEvent *e) + { + mutex.lock(); + newSize = e->size(); + mutex.unlock(); + }; + + QMutex mutex; + QSize newSize; +}; + +class SceneRenderingThread : public QThread +{ + Q_OBJECT +public: + SceneRenderingThread(ThreadSafeGLWidget *widget) + : m_widget(widget) + { + moveToThread(this); + m_size = widget->size(); + } + + void run() { + QTime time; + time.start(); + failure = false; + + m_widget->makeCurrent(); + + while (time.elapsed() < RUNNING_TIME && !failure) { + + + m_widget->mutex.lock(); + QSize s = m_widget->newSize; + m_widget->mutex.unlock(); + + if (s != m_size) { + glViewport(0, 0, s.width(), s.height()); + } + + if (QGLContext::currentContext() != m_widget->context()) { + failure = true; + break; + } + + glClear(GL_COLOR_BUFFER_BIT); + + int w = m_widget->width(); + int h = m_widget->height(); + + renderAScene(w, h); + + int color; + glReadPixels(w / 2, h / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color); + + m_widget->swapBuffers(); + } + + m_widget->doneCurrent(); + } + + bool failure; + +private: + ThreadSafeGLWidget *m_widget; + QSize m_size; +}; + +void tst_QGLThreads::renderInThread_data() +{ + QTest::addColumn("resize"); + QTest::addColumn("update"); + + QTest::newRow("basic") << false << false; + QTest::newRow("with-resize") << true << false; + QTest::newRow("with-update") << false << true; + QTest::newRow("with-resize-and-update") << true << true; +} + +void tst_QGLThreads::renderInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); +#endif + +#ifdef Q_OS_SYMBIAN + QSKIP("OpenGL threading tests are disabled on Symbian as accessing RWindow from a secondary thread is not supported", SkipAll); +#endif + + QFETCH(bool, resize); + QFETCH(bool, update); + + ThreadSafeGLWidget widget; + widget.resize(200, 200); + SceneRenderingThread thread(&widget); + + widget.show(); + QTest::qWaitForWindowShown(&widget); + widget.doneCurrent(); + + thread.start(); + + int value = 10; + while (thread.isRunning()) { + if (resize) + widget.resize(200 + value, 200 + value); + if (update) + widget.update(100 + value, 100 + value, 20, 20); + qApp->processEvents(); + value = -value; + + QThread::msleep(100); + } + + QVERIFY(!thread.failure); +} + +class Device +{ +public: + virtual ~Device() {} + virtual QPaintDevice *realPaintDevice() = 0; + virtual void prepareDevice() {} +}; + +class GLWidgetWrapper : public Device +{ +public: + GLWidgetWrapper() { + widget.resize(150, 150); + widget.show(); + QTest::qWaitForWindowShown(&widget); + widget.doneCurrent(); + } + QPaintDevice *realPaintDevice() { return &widget; } + + ThreadSafeGLWidget widget; +}; + +class PixmapWrapper : public Device +{ +public: + PixmapWrapper() { pixmap = new QPixmap(512, 512); } + ~PixmapWrapper() { delete pixmap; } + QPaintDevice *realPaintDevice() { return pixmap; } + + QPixmap *pixmap; +}; + +class PixelBufferWrapper : public Device +{ +public: + PixelBufferWrapper() { pbuffer = new QGLPixelBuffer(512, 512); } + ~PixelBufferWrapper() { delete pbuffer; } + QPaintDevice *realPaintDevice() { return pbuffer; } + + QGLPixelBuffer *pbuffer; +}; + + +class FrameBufferObjectWrapper : public Device +{ +public: + FrameBufferObjectWrapper() { + widget.makeCurrent(); + fbo = new QGLFramebufferObject(512, 512); + widget.doneCurrent(); + } + ~FrameBufferObjectWrapper() { delete fbo; } + QPaintDevice *realPaintDevice() { return fbo; } + void prepareDevice() { widget.makeCurrent(); } + + ThreadSafeGLWidget widget; + QGLFramebufferObject *fbo; +}; + + +class ThreadPainter : public QObject +{ + Q_OBJECT +public: + ThreadPainter(Device *pd) : device(pd), fail(true) { + pixmap = QPixmap(40, 40); + pixmap.fill(Qt::green); + QPainter p(&pixmap); + p.drawLine(0, 0, 40, 40); + p.drawLine(0, 40, 40, 0); + } + +public slots: + void draw() { + bool beginFailed = false; + QTime time; + time.start(); + int rotAngle = 10; + device->prepareDevice(); + QPaintDevice *paintDevice = device->realPaintDevice(); + QSize s(paintDevice->width(), paintDevice->height()); + while (time.elapsed() < RUNNING_TIME) { + QPainter p; + if (!p.begin(paintDevice)) { + beginFailed = true; + break; + } + p.translate(s.width()/2, s.height()/2); + p.rotate(rotAngle); + p.translate(-s.width()/2, -s.height()/2); + p.fillRect(0, 0, s.width(), s.height(), Qt::red); + QRect rect(QPoint(0, 0), s); + p.drawPixmap(10, 10, pixmap); + p.drawTiledPixmap(50, 50, 100, 100, pixmap); + p.drawText(rect.center(), "This is a piece of text"); + p.end(); + rotAngle += 2; + QThread::msleep(20); + } + + fail = beginFailed; + QThread::currentThread()->quit(); + } + + bool failed() { return fail; } + +private: + QPixmap pixmap; + Device *device; + bool fail; +}; + +template +class PaintThreadManager +{ +public: + PaintThreadManager(int count) : numThreads(count) + { + for (int i=0; imoveToThread(threads.at(i)); + painters.at(i)->connect(threads.at(i), SIGNAL(started()), painters.at(i), SLOT(draw())); + } + } + + ~PaintThreadManager() { + qDeleteAll(threads); + qDeleteAll(painters); + qDeleteAll(devices); + } + + + void start() { + for (int i=0; istart(); + } + + bool areRunning() { + bool running = false; + for (int i=0; iisRunning()) + running = true; + } + + return running; + } + + bool failed() { + for (int i=0; ifailed()) + return true; + } + + return false; + } + +private: + QList threads; + QList devices; + QList painters; + int numThreads; +}; + +/* + This test uses QPainter to draw onto different QGLWidgets in + different threads at the same time. The ThreadSafeGLWidget is + necessary to handle paint and resize events that might come from + the main thread at any time while the test is running. The resize + and paint events would cause makeCurrent() calls to be issued from + within the QGLWidget while the widget's context was current in + another thread, which would cause errors. +*/ +void tst_QGLThreads::painterOnGLWidgetInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); +#endif + if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || + (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { + QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); + } + + PaintThreadManager painterThreads(5); + painterThreads.start(); + + while (painterThreads.areRunning()) { + qApp->processEvents(); + QThread::msleep(100); + } + QVERIFY(!painterThreads.failed()); +} + +/* + This test uses QPainter to draw onto different QPixmaps in + different threads at the same time. +*/ +void tst_QGLThreads::painterOnPixmapInThread() +{ +#ifdef Q_WS_X11 + QSKIP("Drawing text in threads onto X11 drawables currently crashes on some X11 servers.", SkipAll); +#endif + PaintThreadManager painterThreads(5); + painterThreads.start(); + + while (painterThreads.areRunning()) { + qApp->processEvents(); + QThread::msleep(100); + } + QVERIFY(!painterThreads.failed()); +} + +/* This test uses QPainter to draw onto different QGLPixelBuffer + objects in different threads at the same time. +*/ +void tst_QGLThreads::painterOnPboInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); +#endif + if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || + (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { + QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); + return; + } + + if (!QGLPixelBuffer::hasOpenGLPbuffers()) { + QSKIP("This system doesn't support pbuffers.", SkipAll); + return; + } + + PaintThreadManager painterThreads(5); + painterThreads.start(); + + while (painterThreads.areRunning()) { + qApp->processEvents(); + QThread::msleep(100); + } + QVERIFY(!painterThreads.failed()); +} + +/* This test uses QPainter to draw onto different + QGLFramebufferObjects (bound in a QGLWidget's context) in different + threads at the same time. +*/ +void tst_QGLThreads::painterOnFboInThread() +{ +#ifdef Q_OS_MAC + QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); +#endif + if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || + (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { + QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); + return; + } + + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) { + QSKIP("This system doesn't support framebuffer objects.", SkipAll); + return; + } + + PaintThreadManager painterThreads(5); + painterThreads.start(); + + while (painterThreads.areRunning()) { + qApp->processEvents(); + QThread::msleep(100); + } + QVERIFY(!painterThreads.failed()); +} + +int main(int argc, char **argv) +{ + QApplication::setAttribute(Qt::AA_X11InitThreads); + QApplication app(argc, argv); + QTEST_DISABLE_KEYPAD_NAVIGATION \ + + tst_QGLThreads tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_qglthreads.moc" diff --git a/tests/auto/opengl/qglthreads/tst_qglthreads.h b/tests/auto/opengl/qglthreads/tst_qglthreads.h new file mode 100644 index 0000000000..7972638085 --- /dev/null +++ b/tests/auto/opengl/qglthreads/tst_qglthreads.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TST_QGLTHREADS_H +#define TST_QGLTHREADS_H + +#include + +class tst_QGLThreads : public QObject +{ +Q_OBJECT +public: + explicit tst_QGLThreads(QObject *parent = 0); + +private slots: + void swapInThread(); + void textureUploadInThread(); + + void renderInThread_data(); + void renderInThread(); + void painterOnGLWidgetInThread(); + void painterOnPixmapInThread(); + void painterOnPboInThread(); + void painterOnFboInThread(); +}; + +#endif // TST_QGLTHREADS_H diff --git a/tests/auto/qgl/.gitignore b/tests/auto/qgl/.gitignore deleted file mode 100644 index bb6e921035..0000000000 --- a/tests/auto/qgl/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qgl diff --git a/tests/auto/qgl/qgl.pro b/tests/auto/qgl/qgl.pro deleted file mode 100644 index c5e26451ed..0000000000 --- a/tests/auto/qgl/qgl.pro +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# Project file for autotest for file qgl.h -############################################################ - -load(qttest_p4) -requires(contains(QT_CONFIG,opengl)) -QT += widgets widgets-private opengl-private gui-private core-private - -contains(QT_CONFIG,egl):DEFINES += QGL_EGL -win32:!wince*: DEFINES += QT_NO_EGL - -SOURCES += tst_qgl.cpp -RESOURCES = qgl.qrc - -CONFIG+=insignificant_test diff --git a/tests/auto/qgl/qgl.qrc b/tests/auto/qgl/qgl.qrc deleted file mode 100644 index 42281afc98..0000000000 --- a/tests/auto/qgl/qgl.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - ../gui/image/qpixmap/images/designer.png - - diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp deleted file mode 100644 index e1c3462560..0000000000 --- a/tests/auto/qgl/tst_qgl.cpp +++ /dev/null @@ -1,2400 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef QT_BUILD_INTERNAL -#include -#include -#include -#include -#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(); - void threadImages(); - void nullRectCrash(); -}; - -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(1); - QCOMPARE(true, obj1.alpha()); // setAlphaBufferSize() enables alpha. - QCOMPARE(1, obj1.alphaBufferSize()); - QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -2147483648"); - obj1.setAlphaBufferSize(TEST_INT_MIN); - QCOMPARE(1, 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(1); - QCOMPARE(1, obj1.stencilBufferSize()); - QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -2147483648"); - obj1.setStencilBufferSize(TEST_INT_MIN); - QCOMPARE(1, 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) - obj1.setAccumBufferSize(0); - 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()); - - // int QGLFormat::major/minorVersion() - // void QGLFormat::setVersion(int, int) - QCOMPARE(obj1.majorVersion(), 1); - QCOMPARE(obj1.minorVersion(), 0); - obj1.setVersion(3, 2); - QCOMPARE(obj1.majorVersion(), 3); - QCOMPARE(obj1.minorVersion(), 2); - QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 0.1"); - obj1.setVersion(0, 1); - QCOMPARE(obj1.majorVersion(), 3); - QCOMPARE(obj1.minorVersion(), 2); - QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 3.-1"); - obj1.setVersion(3, -1); - QCOMPARE(obj1.majorVersion(), 3); - QCOMPARE(obj1.minorVersion(), 2); - obj1.setVersion(TEST_INT_MAX, TEST_INT_MAX - 1); - QCOMPARE(obj1.majorVersion(), TEST_INT_MAX); - QCOMPARE(obj1.minorVersion(), TEST_INT_MAX - 1); - - - // 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)); - - format1.setVersion(3, 2); - QVERIFY(!(format1 == format2)); - QVERIFY(format1 != format2); - format2.setVersion(3, 2); - QVERIFY(format1 == format2); - QVERIFY(!(format1 != format2)); - - format1.setProfile(QGLFormat::CoreProfile); - QVERIFY(!(format1 == format2)); - QVERIFY(format1 != format2); - format2.setProfile(QGLFormat::CoreProfile); - QVERIFY(format1 == format2); - QVERIFY(!(format1 != format2)); - - format1.setOption(QGL::NoDeprecatedFunctions); - QVERIFY(!(format1 == format2)); - QVERIFY(format1 != format2); - format2.setOption(QGL::NoDeprecatedFunctions); - 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_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); - view.setBackgroundBrush(Qt::white); -#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("doubleBufferedContext"); - QTest::addColumn("autoFillBackground"); - QTest::addColumn("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(); - - 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); - - 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; -} - - -void qt_opengl_draw_test_pattern(QPainter* painter, int width, int height) -{ - 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(); - - painter->setTransform(QTransform()); // reset xform - painter->fillRect(-1, -1, width+2, height+2, Qt::red); // Background - painter->translate(14, 14); - painter->fillPath(intersectingPath, Qt::blue); // Test stencil buffer works - painter->translate(128, 0); - painter->setClipPath(trianglePath); // Test depth buffer works - painter->setTransform(QTransform()); // reset xform ready for fill - painter->fillRect(-1, -1, width+2, height+2, Qt::green); -} - -void qt_opengl_check_test_pattern(const QImage& img) -{ - // 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(img.pixel(39, 64), QColor(Qt::red).rgb()); - QFUZZY_COMPARE_PIXELS(img.pixel(89, 64), QColor(Qt::red).rgb()); - QFUZZY_COMPARE_PIXELS(img.pixel(64, 39), QColor(Qt::blue).rgb()); - QFUZZY_COMPARE_PIXELS(img.pixel(64, 89), QColor(Qt::blue).rgb()); - - QFUZZY_COMPARE_PIXELS(img.pixel(167, 39), QColor(Qt::red).rgb()); - QFUZZY_COMPARE_PIXELS(img.pixel(217, 39), QColor(Qt::red).rgb()); - QFUZZY_COMPARE_PIXELS(img.pixel(192, 64), QColor(Qt::green).rgb()); -} - -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(); - - qt_opengl_draw_test_pattern(&p, width(), height()); - - // 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.resize(256, 128); - 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); - qt_opengl_check_test_pattern(fb); -} - -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); - - QGLFramebufferObject *fbo = new QGLFramebufferObject(200, 100, 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); - - qt_opengl_draw_test_pattern(&fboPainter, fbo->width(), fbo->height()); - - fboPainter.end(); - - QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32); - delete fbo; - - qt_opengl_check_test_pattern(fb); -} - - -// 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(100, 100, 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(100, 100); - 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); - QFUZZY_COMPARE_IMAGES(widgetFB, widgetReference); - - QImage fboReference(w.fboImage.size(), w.fboImage.format()); - fboReference.fill(0xffff0000); - QFUZZY_COMPARE_IMAGES(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); - -#if defined(QGL_EGL) && !defined(Q_WS_X11) - QSKIP("renderPixmap() not yet supported under EGL on your platform", SkipAll); -#endif - - QFUZZY_COMPARE_IMAGES(fb, reference); -} - -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; -#ifdef Q_WS_QWS - glw.setWindowFlags(Qt::FramelessWindowHint); -#endif - 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); - - // Sample pixels in a grid pattern which avoids false failures due to - // off-by-one pixel errors on some buggy GL implementations - for (int x = 25; x < reference.width(); x += 50) { - for (int y = 25; y < reference.width(); y += 50) { - QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); - } - } -} - -class ClipTestGLWidget : public QGLWidget -{ -public: - void paint(QPainter *painter) - { - painter->fillRect(-1, -1, width()+2, height()+2, 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->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(); - } - -protected: - void paintEvent(QPaintEvent*) - { - QPainter painter(this); - paint(&painter); - } -}; - -void tst_QGL::clipTest() -{ - ClipTestGLWidget glw; -#ifdef Q_WS_QWS - glw.setWindowFlags(Qt::FramelessWindowHint); -#endif - 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); - - // Sample pixels in a grid pattern which avoids false failures due to - // off-by-one pixel errors on some buggy GL implementations - for (int x = 2; x < reference.width(); x += 5) { - for (int y = 2; y < reference.height(); y += 5) { - QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y)); - } - } -} - -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: - tst_QGLResource(const QGLContext * = 0) {} - ~tst_QGLResource() { ++deletions; } - - static int deletions; -}; - -int tst_QGLResource::deletions = 0; - -#ifdef TODO -Q_GLOBAL_STATIC(QOpenGLContextGroupResource, qt_shared_test) -#endif //TODO -#endif - -void tst_QGL::shareRegister() -{ -#ifdef TODO -#ifdef QT_BUILD_INTERNAL - // Create a context. - QGLWidget *glw1 = new QGLWidget(); - glw1->makeCurrent(); - - // Nothing should be sharing with glw1's context yet. - QVERIFY(!glw1->isSharing()); - - // Create a guard for the first context. - QOpenGLSharedResourceGuard guard(glw1->context()->contextHandle()); - QVERIFY(guard.id() == 0); - guard.setId(3); - QVERIFY(guard.id() == 3); - - // Request a tst_QGLResource object for the first context. - tst_QGLResource *res1 = qt_shared_test()->value(glw1->context()->contextHandle()); - QVERIFY(res1); - QVERIFY(qt_shared_test()->value(glw1->context()->contextHandle()) == res1); - - // Create another context that shares with the first. - QVERIFY(!glw1->isSharing()); - QGLWidget *glw2 = new QGLWidget(0, glw1); - if (!glw2->isSharing()) { - delete glw2; - delete glw1; - QSKIP("Context sharing is not supported", SkipSingle); - } - QVERIFY(glw1->isSharing()); - 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); - - // 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(); - QVERIFY(!glw3->isSharing()); - - // Create a guard on the standalone context. - QGLSharedResourceGuard guard3(glw3->context()); - guard3.setId(5); - - // Request a resource to the third context. - tst_QGLResource *res3 = qt_shared_test()->value(glw3->context()); - QVERIFY(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); - - // 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 second context should no longer register as sharing. - QVERIFY(!glw2->isSharing()); - - // 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); - - // 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 -#endif //TODO -} - -// Tests QGLContext::bindTexture with default options -void tst_QGL::qglContextDefaultBindTexture() -{ -#ifdef QT_BUILD_INTERNAL - QGLWidget w; - w.makeCurrent(); - QGLContext *ctx = const_cast(w.context()); - - QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); - boundImage->fill(0xFFFFFFFF); - QPixmap *boundPixmap = new QPixmap(256, 256); - boundPixmap->fill(Qt::red); - - int startCacheItemCount = QGLTextureCache::instance()->size(); - - GLuint boundImageTextureId = ctx->bindTexture(*boundImage); - GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap); - - // Make sure the image & pixmap have been added to the cache: - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - // Make sure the image & pixmap have the is_cached flag set: - QVERIFY(QImagePixmapCleanupHooks::isImageCached(*boundImage)); - QVERIFY(QImagePixmapCleanupHooks::isPixmapCached(*boundPixmap)); - - // Make sure the texture IDs returned are valid: - QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE); - QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE); - - // Make sure the textures are still valid after we delete the image/pixmap: - // Also check that although the textures are left intact, the cache entries are removed: - delete boundImage; - boundImage = 0; - QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - delete boundPixmap; - boundPixmap = 0; - QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - // Finally, make sure QGLContext::deleteTexture deletes the texture IDs: - ctx->deleteTexture(boundImageTextureId); - ctx->deleteTexture(boundPixmapTextureId); - QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_FALSE); - QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_FALSE); -#endif -} - -void tst_QGL::textureCleanup() -{ -#ifdef QT_BUILD_INTERNAL - QGLWidget w; - w.resize(200,200); - w.show(); - w.makeCurrent(); - - // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache - // when the pixmap cache is cleared - { - int startCacheItemCount = QGLTextureCache::instance()->size(); - QPainter p(&w); - - QPixmap boundPixmap(":designer.png"); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawPixmap(0, 0, boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - // Check that the texture doesn't get removed from the cache when the pixmap is cleared - // as it should still be in the cache: - boundPixmap = QPixmap(); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - QPixmapCache::clear(); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - } - - // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache - // when they are explicitly removed from the pixmap cache - { - int startCacheItemCount = QGLTextureCache::instance()->size(); - QPainter p(&w); - - QPixmap boundPixmap(128, 128); - QString cacheKey = QString::fromLatin1("myPixmap"); - QPixmapCache::insert(cacheKey, boundPixmap); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawPixmap(0, 0, boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - // Check that the texture doesn't get removed from the cache when the pixmap is cleared - // as it should still be in the cache: - boundPixmap = QPixmap(); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - // Finally, we check that the texture cache entry is removed when we remove the - // pixmap cache entry, which should hold the last reference: - QPixmapCache::remove(cacheKey); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - } - - // Check images & pixmaps are removed from the cache when they are deleted - { - int startCacheItemCount = QGLTextureCache::instance()->size(); - QPainter p(&w); - - QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); - boundImage->fill(0xFFFFFFFF); - QPixmap *boundPixmap = new QPixmap(256, 256); - boundPixmap->fill(Qt::red); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawImage(0, 0, *boundImage); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - p.drawPixmap(0, 0, *boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - delete boundImage; - boundImage = 0; - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - delete boundPixmap; - boundPixmap = 0; - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - } - - // Check images & pixmaps are removed from the cache when they are assigned to - { - int startCacheItemCount = QGLTextureCache::instance()->size(); - QPainter p(&w); - - QImage boundImage(256, 256, QImage::Format_RGB32); - boundImage.fill(0xFFFFFFFF); - QPixmap boundPixmap(256, 256); - boundPixmap.fill(Qt::red); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawImage(0, 0, boundImage); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - p.drawPixmap(0, 0, boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - boundImage = QImage(64, 64, QImage::Format_RGB32); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - boundPixmap = QPixmap(64, 64); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - } - - // Check images & pixmaps are removed from the cache when they are modified (detached) - { - int startCacheItemCount = QGLTextureCache::instance()->size(); - QPainter p(&w); - - QImage boundImage(256, 256, QImage::Format_RGB32); - boundImage.fill(0xFFFFFFFF); - QPixmap boundPixmap(256, 256); - boundPixmap.fill(Qt::red); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawImage(0, 0, boundImage); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - p.drawPixmap(0, 0, boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - boundImage.fill(0x00000000); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - boundPixmap.fill(Qt::blue); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - } - - // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made - QImage copyOfImage; - QPixmap copyOfPixmap; - int startCacheItemCount = QGLTextureCache::instance()->size(); - { - QPainter p(&w); - - QImage boundImage(256, 256, QImage::Format_RGB32); - boundImage.fill(0xFFFFFFFF); - QPixmap boundPixmap(256, 256); - boundPixmap.fill(Qt::red); - - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); - - p.drawImage(0, 0, boundImage); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - p.drawPixmap(0, 0, boundPixmap); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - // Need to call end for the GL2 paint engine to release references to pixmap if using tfp - p.end(); - - copyOfImage = boundImage; - copyOfPixmap = boundPixmap; - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - } // boundImage & boundPixmap would have been deleted when they went out of scope - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); - - copyOfImage = QImage(); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); - - copyOfPixmap = QPixmap(); - QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); -#endif -} - -namespace ThreadImages { - -class Producer : public QObject -{ - Q_OBJECT -public: - Producer() - { - startTimer(20); - - QThread *thread = new QThread; - thread->start(); - - connect(this, SIGNAL(destroyed()), thread, SLOT(quit())); - - moveToThread(thread); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - } - -signals: - void imageReady(const QImage &image); - -protected: - void timerEvent(QTimerEvent *) - { - QImage image(256, 256, QImage::Format_RGB32); - QLinearGradient g(0, 0, 0, 256); - g.setColorAt(0, QColor(255, 180, 180)); - g.setColorAt(1, Qt::white); - g.setSpread(QGradient::ReflectSpread); - - QBrush brush(g); - brush.setTransform(QTransform::fromTranslate(0, delta)); - delta += 10; - - QPainter p(&image); - p.fillRect(image.rect(), brush); - - if (images.size() > 10) - images.removeFirst(); - - images.append(image); - - emit imageReady(image); - } - -private: - QList images; - int delta; -}; - - -class DisplayWidget : public QGLWidget -{ - Q_OBJECT -public: - DisplayWidget(QWidget *parent) : QGLWidget(parent) {} - void paintEvent(QPaintEvent *) - { - QPainter p(this); - p.drawImage(rect(), m_image); - } - -public slots: - void setImage(const QImage &image) - { - m_image = image; - update(); - } - -private: - QImage m_image; -}; - -class Widget : public QWidget -{ - Q_OBJECT -public: - Widget() - : iterations(0) - , display(0) - , producer(new Producer) - { - startTimer(400); - connect(this, SIGNAL(destroyed()), producer, SLOT(deleteLater())); - } - - int iterations; - -protected: - void timerEvent(QTimerEvent *) - { - ++iterations; - - delete display; - display = new DisplayWidget(this); - connect(producer, SIGNAL(imageReady(const QImage &)), display, SLOT(setImage(const QImage &))); - - display->setGeometry(rect()); - display->show(); - } - -private: - DisplayWidget *display; - Producer *producer; -}; - -} - -void tst_QGL::threadImages() -{ - ThreadImages::Widget *widget = new ThreadImages::Widget; - widget->show(); - - while (widget->iterations <= 5) { - qApp->processEvents(); - } - - delete widget; -} - -void tst_QGL::nullRectCrash() -{ - if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) - QSKIP("QGLFramebufferObject not supported on this platform", SkipSingle); - - QGLWidget glw; - glw.makeCurrent(); - - QGLFramebufferObjectFormat fboFormat; - fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - - QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat); - - QPainter fboPainter(fbo); - - fboPainter.setPen(QPen(QColor(255, 127, 127, 127), 2)); - fboPainter.setBrush(QColor(127, 255, 127, 127)); - fboPainter.drawRect(QRectF()); - - fboPainter.end(); -} - -class tst_QGLDummy : public QObject -{ -Q_OBJECT - -public: - tst_QGLDummy() {} - -private slots: - void qglSkipTests() { - QSKIP("QGL not supported on this system.", SkipAll); - } -}; - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - QTEST_DISABLE_KEYPAD_NAVIGATION \ - QGLWidget glWidget; - if (!glWidget.isValid()) { - tst_QGLDummy tc; - return QTest::qExec(&tc, argc, argv); - } - tst_QGL tc; - return QTest::qExec(&tc, argc, argv); -} - -#include "tst_qgl.moc" diff --git a/tests/auto/qglbuffer/qglbuffer.pro b/tests/auto/qglbuffer/qglbuffer.pro deleted file mode 100644 index 48bd966797..0000000000 --- a/tests/auto/qglbuffer/qglbuffer.pro +++ /dev/null @@ -1,11 +0,0 @@ -############################################################ -# Project file for autotest for file qglbuffer.h -############################################################ - -load(qttest_p4) -requires(contains(QT_CONFIG,opengl)) -QT += opengl widgets - -win32:!wince*: DEFINES += QT_NO_EGL - -SOURCES += tst_qglbuffer.cpp diff --git a/tests/auto/qglbuffer/tst_qglbuffer.cpp b/tests/auto/qglbuffer/tst_qglbuffer.cpp deleted file mode 100644 index 9215b5fedd..0000000000 --- a/tests/auto/qglbuffer/tst_qglbuffer.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include - -class tst_QGLBuffer : public QObject -{ - Q_OBJECT -public: - tst_QGLBuffer() {} - ~tst_QGLBuffer() {} - -private slots: - void vertexBuffer_data(); - void vertexBuffer(); - void indexBuffer_data(); - void indexBuffer(); - void bufferSharing(); - -private: - void testBuffer(QGLBuffer::Type type); -}; - -void tst_QGLBuffer::vertexBuffer_data() -{ - QTest::addColumn("usagePattern"); - - QTest::newRow("StreamDraw") << int(QGLBuffer::StreamDraw); - QTest::newRow("StaticDraw") << int(QGLBuffer::StaticDraw); - QTest::newRow("DynamicDraw") << int(QGLBuffer::DynamicDraw); -} - -void tst_QGLBuffer::vertexBuffer() -{ - testBuffer(QGLBuffer::VertexBuffer); -} - -void tst_QGLBuffer::indexBuffer_data() -{ - vertexBuffer_data(); -} - -void tst_QGLBuffer::indexBuffer() -{ - testBuffer(QGLBuffer::IndexBuffer); -} - -void tst_QGLBuffer::testBuffer(QGLBuffer::Type type) -{ - QFETCH(int, usagePattern); - - QGLWidget w; - w.makeCurrent(); - - // Create the local object, but not the buffer in the server. - QGLBuffer buffer(type); - QVERIFY(buffer.usagePattern() == QGLBuffer::StaticDraw); - buffer.setUsagePattern(QGLBuffer::UsagePattern(usagePattern)); - - // Check the initial state. - QVERIFY(buffer.type() == type); - QVERIFY(!buffer.isCreated()); - QVERIFY(buffer.bufferId() == 0); - QVERIFY(buffer.usagePattern() == QGLBuffer::UsagePattern(usagePattern)); - QCOMPARE(buffer.size(), -1); - - // Should not be able to bind it yet because it isn't created. - QVERIFY(!buffer.bind()); - - // Create the buffer - if this fails, then assume that the - // GL implementation does not support buffers at all. - if (!buffer.create()) - QSKIP("Buffers are not supported on this platform", SkipAll); - - // Should now have a buffer id. - QVERIFY(buffer.bufferId() != 0); - - // Bind the buffer and upload some data. - QVERIFY(buffer.bind()); - static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - buffer.allocate(data, sizeof(data)); - - // Check the buffer size. - QCOMPARE(buffer.size(), int(sizeof(data))); - - // Map the buffer and read back its contents. - bool haveMap = false; - GLfloat *mapped = reinterpret_cast - (buffer.map(QGLBuffer::ReadOnly)); - if (mapped) { - for (int index = 0; index < 9; ++index) - QCOMPARE(mapped[index], data[index]); - buffer.unmap(); - haveMap = true; - } else { - qWarning("QGLBuffer::map() is not supported on this platform"); - } - - // Read back the buffer contents using read(). - bool haveRead = false; - GLfloat readdata[9]; - if (buffer.read(0, readdata, sizeof(readdata))) { - for (int index = 0; index < 9; ++index) - QCOMPARE(readdata[index], data[index]); - haveRead = true; - } else { - qWarning("QGLBuffer::read() is not supported on this platform"); - } - - // Write some different data to a specific location and check it. - static GLfloat const diffdata[] = {11, 12, 13}; - buffer.write(sizeof(GLfloat) * 3, diffdata, sizeof(diffdata)); - if (haveMap) { - mapped = reinterpret_cast(buffer.map(QGLBuffer::ReadOnly)); - QVERIFY(mapped != 0); - for (int index = 0; index < 9; ++index) { - if (index >= 3 && index <= 5) - QCOMPARE(mapped[index], diffdata[index - 3]); - else - QCOMPARE(mapped[index], data[index]); - } - buffer.unmap(); - } - if (haveRead) { - QVERIFY(buffer.read(0, readdata, sizeof(readdata))); - for (int index = 0; index < 9; ++index) { - if (index >= 3 && index <= 5) - QCOMPARE(readdata[index], diffdata[index - 3]); - else - QCOMPARE(readdata[index], data[index]); - } - } - - // Write to the buffer using the return value from map. - if (haveMap) { - mapped = reinterpret_cast(buffer.map(QGLBuffer::WriteOnly)); - QVERIFY(mapped != 0); - mapped[6] = 14; - buffer.unmap(); - - mapped = reinterpret_cast(buffer.map(QGLBuffer::ReadOnly)); - QVERIFY(mapped != 0); - static GLfloat const diff2data[] = {11, 12, 13, 14}; - for (int index = 0; index < 9; ++index) { - if (index >= 3 && index <= 6) - QCOMPARE(mapped[index], diff2data[index - 3]); - else - QCOMPARE(mapped[index], data[index]); - } - buffer.unmap(); - } - - // Resize the buffer. - buffer.allocate(sizeof(GLfloat) * 20); - QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 20)); - buffer.allocate(0, sizeof(GLfloat) * 32); - QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 32)); - - // Release the buffer. - buffer.release(); -} - -void tst_QGLBuffer::bufferSharing() -{ - QGLWidget *w1 = new QGLWidget(); - w1->makeCurrent(); - - QGLWidget *w2 = new QGLWidget(0, w1); - if (!w2->isSharing()) { - delete w2; - delete w1; - QSKIP("Context sharing is not supported on this platform", SkipSingle); - } - - // Bind the buffer in the first context and write some data to it. - QGLBuffer buffer(QGLBuffer::VertexBuffer); - if (!buffer.create()) - QSKIP("Buffers are not supported on this platform", SkipSingle); - QVERIFY(buffer.isCreated()); - QVERIFY(buffer.bind()); - static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - buffer.allocate(data, sizeof(data)); - QCOMPARE(buffer.size(), int(sizeof(data))); - buffer.release(); - - // Bind the buffer in the second context and read back the data. - w2->makeCurrent(); - QVERIFY(buffer.bind()); - QCOMPARE(buffer.size(), int(sizeof(data))); - GLfloat readdata[9]; - if (buffer.read(0, readdata, sizeof(readdata))) { - for (int index = 0; index < 9; ++index) - QCOMPARE(readdata[index], data[index]); - } - buffer.release(); - - // Delete the first context. - delete w1; - - // Make the second context current again because deleting the first - // one will call doneCurrent() even though it wasn't current! - w2->makeCurrent(); - - // The buffer should still be valid in the second context. - QVERIFY(buffer.bufferId() != 0); - QVERIFY(buffer.isCreated()); - QVERIFY(buffer.bind()); - QCOMPARE(buffer.size(), int(sizeof(data))); - buffer.release(); - - // Delete the second context. - delete w2; - - // The buffer should now be invalid. - QVERIFY(buffer.bufferId() == 0); - QVERIFY(!buffer.isCreated()); -} - -QTEST_MAIN(tst_QGLBuffer) - -#include "tst_qglbuffer.moc" diff --git a/tests/auto/qglfunctions/qglfunctions.pro b/tests/auto/qglfunctions/qglfunctions.pro deleted file mode 100644 index 9fe8de2b23..0000000000 --- a/tests/auto/qglfunctions/qglfunctions.pro +++ /dev/null @@ -1,7 +0,0 @@ -load(qttest_p4) -requires(contains(QT_CONFIG,opengl)) -QT += opengl widgets - -win32:!wince*: DEFINES += QT_NO_EGL - -SOURCES += tst_qglfunctions.cpp diff --git a/tests/auto/qglfunctions/tst_qglfunctions.cpp b/tests/auto/qglfunctions/tst_qglfunctions.cpp deleted file mode 100644 index ec87f6f857..0000000000 --- a/tests/auto/qglfunctions/tst_qglfunctions.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include - -class tst_QGLFunctions : public QObject -{ - Q_OBJECT -public: - tst_QGLFunctions() {} - ~tst_QGLFunctions() {} - -private slots: - void features(); - void multitexture(); - void blendColor(); - -private: - static bool hasExtension(const char *name); -}; - -bool tst_QGLFunctions::hasExtension(const char *name) -{ - QString extensions = - QString::fromLatin1 - (reinterpret_cast(glGetString(GL_EXTENSIONS))); - return extensions.split(QLatin1Char(' ')).contains - (QString::fromLatin1(name)); -} - -// Check that the reported features are consistent with the platform. -void tst_QGLFunctions::features() -{ - // Before being associated with a context, there should be - // no features enabled. - QGLFunctions funcs; - QVERIFY(!funcs.openGLFeatures()); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Shaders)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Buffers)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Framebuffers)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendEquation)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Multisample)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures)); - - // Make a context current. - QGLWidget glw; - if (!glw.isValid()) - QSKIP("Could not create a GL context", SkipAll); - glw.makeCurrent(); - funcs.initializeGLFunctions(); - - // Validate the features against what we expect for this platform. -#if defined(QT_OPENGL_ES_2) - QGLFunctions::OpenGLFeatures allFeatures = - (QGLFunctions::Multitexture | - QGLFunctions::Shaders | - QGLFunctions::Buffers | - QGLFunctions::Framebuffers | - QGLFunctions::BlendColor | - QGLFunctions::BlendEquation | - QGLFunctions::BlendEquationSeparate | - QGLFunctions::BlendFuncSeparate | - QGLFunctions::BlendSubtract | - QGLFunctions::CompressedTextures | - QGLFunctions::Multisample | - QGLFunctions::StencilSeparate | - QGLFunctions::NPOTTextures); - QVERIFY((funcs.openGLFeatures() & allFeatures) == allFeatures); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Shaders)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Buffers)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendEquation)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multisample)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures)); -#elif defined(QT_OPENGL_ES) - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multitexture)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Buffers)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures)); - QVERIFY(funcs.hasOpenGLFeature(QGLFunctions::Multisample)); - - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::Shaders)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)); - QVERIFY(!funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate)); - - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers), - hasExtension("GL_OES_framebuffer_object")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate), - hasExtension("GL_OES_blend_equation_separate")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate), - hasExtension("GL_OES_blend_func_separate")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract), - hasExtension("GL_OES_blend_subtract")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures), - hasExtension("GL_OES_texture_npot")); -#else - // We check for both the extension name and the minimum OpenGL version - // for the feature. This will help us catch situations where a platform - // doesn't list an extension by name but does have the feature by virtue - // of its version number. - QGLFormat::OpenGLVersionFlags versions = QGLFormat::openGLVersionFlags(); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Multitexture), - hasExtension("GL_ARB_multitexture") || - (versions & QGLFormat::OpenGL_Version_1_3) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Shaders), - hasExtension("GL_ARB_shader_objects") || - (versions & QGLFormat::OpenGL_Version_2_0) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Buffers), - (versions & QGLFormat::OpenGL_Version_1_5) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Framebuffers), - hasExtension("GL_EXT_framebuffer_object") || - hasExtension("GL_ARB_framebuffer_object")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendColor), - hasExtension("GL_EXT_blend_color") || - (versions & QGLFormat::OpenGL_Version_1_2) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquation), - (versions & QGLFormat::OpenGL_Version_1_2) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendEquationSeparate), - hasExtension("GL_EXT_blend_equation_separate") || - (versions & QGLFormat::OpenGL_Version_2_0) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendFuncSeparate), - hasExtension("GL_EXT_blend_func_separate") || - (versions & QGLFormat::OpenGL_Version_1_4) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::BlendSubtract), - hasExtension("GL_EXT_blend_subtract")); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::CompressedTextures), - hasExtension("GL_ARB_texture_compression") || - (versions & QGLFormat::OpenGL_Version_1_3) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::Multisample), - hasExtension("GL_ARB_multisample") || - (versions & QGLFormat::OpenGL_Version_1_3) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::StencilSeparate), - (versions & QGLFormat::OpenGL_Version_2_0) != 0); - QCOMPARE(funcs.hasOpenGLFeature(QGLFunctions::NPOTTextures), - hasExtension("GL_ARB_texture_non_power_of_two") || - (versions & QGLFormat::OpenGL_Version_2_0) != 0); -#endif -} - -// Verify that the multitexture functions appear to resolve and work. -void tst_QGLFunctions::multitexture() -{ - QGLFunctions funcs; - QGLWidget glw; - if (!glw.isValid()) - QSKIP("Could not create a GL context", SkipAll); - glw.makeCurrent(); - funcs.initializeGLFunctions(); - - if (!funcs.hasOpenGLFeature(QGLFunctions::Multitexture)) - QSKIP("Multitexture functions are not supported", SkipSingle); - - funcs.glActiveTexture(GL_TEXTURE1); - - GLint active = 0; - glGetIntegerv(GL_ACTIVE_TEXTURE, &active); - QVERIFY(active == GL_TEXTURE1); - - funcs.glActiveTexture(GL_TEXTURE0); - - active = 0; - glGetIntegerv(GL_ACTIVE_TEXTURE, &active); - QVERIFY(active == GL_TEXTURE0); -} - -// Verify that the glBlendColor() function appears to resolve and work. -void tst_QGLFunctions::blendColor() -{ - QGLFunctions funcs; - QGLWidget glw; - if (!glw.isValid()) - QSKIP("Could not create a GL context", SkipAll); - glw.makeCurrent(); - funcs.initializeGLFunctions(); - - if (!funcs.hasOpenGLFeature(QGLFunctions::BlendColor)) - QSKIP("glBlendColor() is not supported", SkipSingle); - - funcs.glBlendColor(0.0f, 1.0f, 0.0f, 1.0f); - - GLfloat colors[4] = {0.5f, 0.5f, 0.5f, 0.5f}; - glGetFloatv(GL_BLEND_COLOR, colors); - - QCOMPARE(colors[0], 0.0f); - QCOMPARE(colors[1], 1.0f); - QCOMPARE(colors[2], 0.0f); - QCOMPARE(colors[3], 1.0f); -} - -QTEST_MAIN(tst_QGLFunctions) - -#include "tst_qglfunctions.moc" diff --git a/tests/auto/qglthreads/qglthreads.pro b/tests/auto/qglthreads/qglthreads.pro deleted file mode 100644 index d2fd31411f..0000000000 --- a/tests/auto/qglthreads/qglthreads.pro +++ /dev/null @@ -1,14 +0,0 @@ -load(qttest_p4) -requires(contains(QT_CONFIG,opengl)) -QT += opengl widgets - -win32:!wince*: DEFINES += QT_NO_EGL - -HEADERS += tst_qglthreads.h -SOURCES += tst_qglthreads.cpp - -x11 { - LIBS += $$QMAKE_LIBS_X11 -} - -CONFIG+=insignificant_test diff --git a/tests/auto/qglthreads/tst_qglthreads.cpp b/tests/auto/qglthreads/tst_qglthreads.cpp deleted file mode 100644 index ee05e406c8..0000000000 --- a/tests/auto/qglthreads/tst_qglthreads.cpp +++ /dev/null @@ -1,758 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include -#include "tst_qglthreads.h" - -#ifdef Q_OS_SYMBIAN -#define RUNNING_TIME 2000 // save GPU mem by running shorter time. -#else -#define RUNNING_TIME 5000 -#endif - - - - -tst_QGLThreads::tst_QGLThreads(QObject *parent) - : QObject(parent) -{ -} - -/* - - swapInThread - - The purpose of this testcase is to verify that it is possible to do rendering into - a GL context from the GUI thread, then swap the contents in from a background thread. - - The usecase for this is to have the background thread do the waiting for vertical - sync while the GUI thread is idle. - - Currently the locking is handled directly in the paintEvent(). For the actual usecase - in Qt, the locking is done in the windowsurface before starting any drawing while - unlocking is done after all drawing has been done. - */ - - -class SwapThread : public QThread -{ - Q_OBJECT -public: - SwapThread(QGLWidget *widget) - : m_widget(widget) - { - moveToThread(this); - } - - void run() { - QTime time; - time.start(); - while (time.elapsed() < RUNNING_TIME) { - lock(); - wait(); - - m_widget->makeCurrent(); - m_widget->swapBuffers(); - m_widget->doneCurrent(); - unlock(); - } - } - - void lock() { m_mutex.lock(); } - void unlock() { m_mutex.unlock(); } - - void wait() { m_wait_condition.wait(&m_mutex); } - void notify() { m_wait_condition.wakeAll(); } - -private: - QGLWidget *m_widget; - QMutex m_mutex; - QWaitCondition m_wait_condition; -}; - -class ForegroundWidget : public QGLWidget -{ -public: - ForegroundWidget(const QGLFormat &format) - : QGLWidget(format), m_thread(0) - { - setAutoBufferSwap(false); - } - - void paintEvent(QPaintEvent *) - { - m_thread->lock(); - makeCurrent(); - QPainter p(this); - p.fillRect(rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); - p.setPen(Qt::red); - p.setFont(QFont("SansSerif", 24)); - p.drawText(rect(), Qt::AlignCenter, "This is an autotest"); - p.end(); - doneCurrent(); - m_thread->notify(); - m_thread->unlock(); - - update(); - } - - void setThread(SwapThread *thread) { - m_thread = thread; - } - - SwapThread *m_thread; -}; - -void tst_QGLThreads::swapInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); -#endif - - QGLFormat format; - format.setSwapInterval(1); - ForegroundWidget widget(format); - SwapThread thread(&widget); - widget.setThread(&thread); - widget.show(); - - QTest::qWaitForWindowShown(&widget); - thread.start(); - - while (thread.isRunning()) { - qApp->processEvents(); - } - - widget.hide(); - - QVERIFY(true); -} - - - - - - - -/* - textureUploadInThread - - The purpose of this testcase is to verify that doing texture uploads in a background - thread is possible and that it works. - */ - -class CreateAndUploadThread : public QThread -{ - Q_OBJECT -public: - CreateAndUploadThread(QGLWidget *shareWidget) - { - m_gl = new QGLWidget(0, shareWidget); - moveToThread(this); - } - - ~CreateAndUploadThread() - { - delete m_gl; - } - - void run() { - m_gl->makeCurrent(); - QTime time; - time.start(); - while (time.elapsed() < RUNNING_TIME) { - int width = 400; - int height = 300; -#ifdef Q_OS_SYMBIAN - // GPU mem is very scarce resource on Symbian currently. - // That's why we create only small textures. - width = 50; - height = 20; -#endif - QImage image(width, height, QImage::Format_RGB32); - QPainter p(&image); - p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256)); - p.setPen(Qt::red); - p.setFont(QFont("SansSerif", 24)); - p.drawText(image.rect(), Qt::AlignCenter, "This is an autotest"); - p.end(); - m_gl->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); - - createdAndUploaded(image); - } - } - -signals: - void createdAndUploaded(const QImage &image); - -private: - QGLWidget *m_gl; -}; - -class TextureDisplay : public QGLWidget -{ - Q_OBJECT -public: - void paintEvent(QPaintEvent *) { - QPainter p(this); - for (int i=0; i 100) { - m_images.takeFirst(); - m_positions.takeFirst(); - } - } - -private: - QList m_images; - QList m_positions; -}; - -void tst_QGLThreads::textureUploadInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll); -#endif - - TextureDisplay display; - CreateAndUploadThread thread(&display); - - connect(&thread, SIGNAL(createdAndUploaded(QImage)), &display, SLOT(receiveImage(QImage))); - - display.show(); - QTest::qWaitForWindowShown(&display); - - thread.start(); - - while (thread.isRunning()) { - qApp->processEvents(); - } - - QVERIFY(true); -} - - - - - - -/* - renderInThread - - This test sets up a scene and renders it in a different thread. - For simplicity, the scene is simply a bunch of rectangles, but - if that works, we're in good shape.. - */ - -static inline float qrandom() { return (rand() % 100) / 100.f; } - -void renderAScene(int w, int h) -{ -#ifdef QT_OPENGL_ES_2 - QGLShaderProgram program; - program.addShaderFromSourceCode(QGLShader::Vertex, "attribute highp vec2 pos; void main() { gl_Position = vec4(pos.xy, 1.0, 1.0); }"); - program.addShaderFromSourceCode(QGLShader::Fragment, "uniform lowp vec4 color; void main() { gl_FragColor = color; }"); - program.bindAttributeLocation("pos", 0); - program.bind(); - int colorId = program.uniformLocation("color"); - - glEnableVertexAttribArray(0); - - for (int i=0; i<1000; ++i) { - GLfloat pos[] = { - (rand() % 100) / 100., - (rand() % 100) / 100., - (rand() % 100) / 100., - (rand() % 100) / 100., - (rand() % 100) / 100., - (rand() % 100) / 100. - }; - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, pos); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); - } -#else - glViewport(0, 0, w, h); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(0, w, h, 0, 1, 100); - glTranslated(0, 0, -1); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - for (int i=0;i<1000; ++i) { - glBegin(GL_TRIANGLES); - glColor3f(qrandom(), qrandom(), qrandom()); - glVertex2f(qrandom() * w, qrandom() * h); - glColor3f(qrandom(), qrandom(), qrandom()); - glVertex2f(qrandom() * w, qrandom() * h); - glColor3f(qrandom(), qrandom(), qrandom()); - glVertex2f(qrandom() * w, qrandom() * h); - glEnd(); - } -#endif -} - -class ThreadSafeGLWidget : public QGLWidget -{ -public: - ThreadSafeGLWidget(QWidget *parent = 0) : QGLWidget(parent) {} - void paintEvent(QPaintEvent *) - { - // ignored as we're anyway swapping as fast as we can - }; - - void resizeEvent(QResizeEvent *e) - { - mutex.lock(); - newSize = e->size(); - mutex.unlock(); - }; - - QMutex mutex; - QSize newSize; -}; - -class SceneRenderingThread : public QThread -{ - Q_OBJECT -public: - SceneRenderingThread(ThreadSafeGLWidget *widget) - : m_widget(widget) - { - moveToThread(this); - m_size = widget->size(); - } - - void run() { - QTime time; - time.start(); - failure = false; - - m_widget->makeCurrent(); - - while (time.elapsed() < RUNNING_TIME && !failure) { - - - m_widget->mutex.lock(); - QSize s = m_widget->newSize; - m_widget->mutex.unlock(); - - if (s != m_size) { - glViewport(0, 0, s.width(), s.height()); - } - - if (QGLContext::currentContext() != m_widget->context()) { - failure = true; - break; - } - - glClear(GL_COLOR_BUFFER_BIT); - - int w = m_widget->width(); - int h = m_widget->height(); - - renderAScene(w, h); - - int color; - glReadPixels(w / 2, h / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color); - - m_widget->swapBuffers(); - } - - m_widget->doneCurrent(); - } - - bool failure; - -private: - ThreadSafeGLWidget *m_widget; - QSize m_size; -}; - -void tst_QGLThreads::renderInThread_data() -{ - QTest::addColumn("resize"); - QTest::addColumn("update"); - - QTest::newRow("basic") << false << false; - QTest::newRow("with-resize") << true << false; - QTest::newRow("with-update") << false << true; - QTest::newRow("with-resize-and-update") << true << true; -} - -void tst_QGLThreads::renderInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); -#endif - -#ifdef Q_OS_SYMBIAN - QSKIP("OpenGL threading tests are disabled on Symbian as accessing RWindow from a secondary thread is not supported", SkipAll); -#endif - - QFETCH(bool, resize); - QFETCH(bool, update); - - ThreadSafeGLWidget widget; - widget.resize(200, 200); - SceneRenderingThread thread(&widget); - - widget.show(); - QTest::qWaitForWindowShown(&widget); - widget.doneCurrent(); - - thread.start(); - - int value = 10; - while (thread.isRunning()) { - if (resize) - widget.resize(200 + value, 200 + value); - if (update) - widget.update(100 + value, 100 + value, 20, 20); - qApp->processEvents(); - value = -value; - - QThread::msleep(100); - } - - QVERIFY(!thread.failure); -} - -class Device -{ -public: - virtual ~Device() {} - virtual QPaintDevice *realPaintDevice() = 0; - virtual void prepareDevice() {} -}; - -class GLWidgetWrapper : public Device -{ -public: - GLWidgetWrapper() { - widget.resize(150, 150); - widget.show(); - QTest::qWaitForWindowShown(&widget); - widget.doneCurrent(); - } - QPaintDevice *realPaintDevice() { return &widget; } - - ThreadSafeGLWidget widget; -}; - -class PixmapWrapper : public Device -{ -public: - PixmapWrapper() { pixmap = new QPixmap(512, 512); } - ~PixmapWrapper() { delete pixmap; } - QPaintDevice *realPaintDevice() { return pixmap; } - - QPixmap *pixmap; -}; - -class PixelBufferWrapper : public Device -{ -public: - PixelBufferWrapper() { pbuffer = new QGLPixelBuffer(512, 512); } - ~PixelBufferWrapper() { delete pbuffer; } - QPaintDevice *realPaintDevice() { return pbuffer; } - - QGLPixelBuffer *pbuffer; -}; - - -class FrameBufferObjectWrapper : public Device -{ -public: - FrameBufferObjectWrapper() { - widget.makeCurrent(); - fbo = new QGLFramebufferObject(512, 512); - widget.doneCurrent(); - } - ~FrameBufferObjectWrapper() { delete fbo; } - QPaintDevice *realPaintDevice() { return fbo; } - void prepareDevice() { widget.makeCurrent(); } - - ThreadSafeGLWidget widget; - QGLFramebufferObject *fbo; -}; - - -class ThreadPainter : public QObject -{ - Q_OBJECT -public: - ThreadPainter(Device *pd) : device(pd), fail(true) { - pixmap = QPixmap(40, 40); - pixmap.fill(Qt::green); - QPainter p(&pixmap); - p.drawLine(0, 0, 40, 40); - p.drawLine(0, 40, 40, 0); - } - -public slots: - void draw() { - bool beginFailed = false; - QTime time; - time.start(); - int rotAngle = 10; - device->prepareDevice(); - QPaintDevice *paintDevice = device->realPaintDevice(); - QSize s(paintDevice->width(), paintDevice->height()); - while (time.elapsed() < RUNNING_TIME) { - QPainter p; - if (!p.begin(paintDevice)) { - beginFailed = true; - break; - } - p.translate(s.width()/2, s.height()/2); - p.rotate(rotAngle); - p.translate(-s.width()/2, -s.height()/2); - p.fillRect(0, 0, s.width(), s.height(), Qt::red); - QRect rect(QPoint(0, 0), s); - p.drawPixmap(10, 10, pixmap); - p.drawTiledPixmap(50, 50, 100, 100, pixmap); - p.drawText(rect.center(), "This is a piece of text"); - p.end(); - rotAngle += 2; - QThread::msleep(20); - } - - fail = beginFailed; - QThread::currentThread()->quit(); - } - - bool failed() { return fail; } - -private: - QPixmap pixmap; - Device *device; - bool fail; -}; - -template -class PaintThreadManager -{ -public: - PaintThreadManager(int count) : numThreads(count) - { - for (int i=0; imoveToThread(threads.at(i)); - painters.at(i)->connect(threads.at(i), SIGNAL(started()), painters.at(i), SLOT(draw())); - } - } - - ~PaintThreadManager() { - qDeleteAll(threads); - qDeleteAll(painters); - qDeleteAll(devices); - } - - - void start() { - for (int i=0; istart(); - } - - bool areRunning() { - bool running = false; - for (int i=0; iisRunning()) - running = true; - } - - return running; - } - - bool failed() { - for (int i=0; ifailed()) - return true; - } - - return false; - } - -private: - QList threads; - QList devices; - QList painters; - int numThreads; -}; - -/* - This test uses QPainter to draw onto different QGLWidgets in - different threads at the same time. The ThreadSafeGLWidget is - necessary to handle paint and resize events that might come from - the main thread at any time while the test is running. The resize - and paint events would cause makeCurrent() calls to be issued from - within the QGLWidget while the widget's context was current in - another thread, which would cause errors. -*/ -void tst_QGLThreads::painterOnGLWidgetInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); -#endif - if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || - (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { - QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); - } - - PaintThreadManager painterThreads(5); - painterThreads.start(); - - while (painterThreads.areRunning()) { - qApp->processEvents(); - QThread::msleep(100); - } - QVERIFY(!painterThreads.failed()); -} - -/* - This test uses QPainter to draw onto different QPixmaps in - different threads at the same time. -*/ -void tst_QGLThreads::painterOnPixmapInThread() -{ -#ifdef Q_WS_X11 - QSKIP("Drawing text in threads onto X11 drawables currently crashes on some X11 servers.", SkipAll); -#endif - PaintThreadManager painterThreads(5); - painterThreads.start(); - - while (painterThreads.areRunning()) { - qApp->processEvents(); - QThread::msleep(100); - } - QVERIFY(!painterThreads.failed()); -} - -/* This test uses QPainter to draw onto different QGLPixelBuffer - objects in different threads at the same time. -*/ -void tst_QGLThreads::painterOnPboInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); -#endif - if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || - (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { - QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); - return; - } - - if (!QGLPixelBuffer::hasOpenGLPbuffers()) { - QSKIP("This system doesn't support pbuffers.", SkipAll); - return; - } - - PaintThreadManager painterThreads(5); - painterThreads.start(); - - while (painterThreads.areRunning()) { - qApp->processEvents(); - QThread::msleep(100); - } - QVERIFY(!painterThreads.failed()); -} - -/* This test uses QPainter to draw onto different - QGLFramebufferObjects (bound in a QGLWidget's context) in different - threads at the same time. -*/ -void tst_QGLThreads::painterOnFboInThread() -{ -#ifdef Q_OS_MAC - QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll); -#endif - if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) || - (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) { - QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll); - return; - } - - if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) { - QSKIP("This system doesn't support framebuffer objects.", SkipAll); - return; - } - - PaintThreadManager painterThreads(5); - painterThreads.start(); - - while (painterThreads.areRunning()) { - qApp->processEvents(); - QThread::msleep(100); - } - QVERIFY(!painterThreads.failed()); -} - -int main(int argc, char **argv) -{ - QApplication::setAttribute(Qt::AA_X11InitThreads); - QApplication app(argc, argv); - QTEST_DISABLE_KEYPAD_NAVIGATION \ - - tst_QGLThreads tc; - return QTest::qExec(&tc, argc, argv); -} - -#include "tst_qglthreads.moc" diff --git a/tests/auto/qglthreads/tst_qglthreads.h b/tests/auto/qglthreads/tst_qglthreads.h deleted file mode 100644 index 7972638085..0000000000 --- a/tests/auto/qglthreads/tst_qglthreads.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 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$ -** GNU Lesser General Public License Usage -** 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. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef TST_QGLTHREADS_H -#define TST_QGLTHREADS_H - -#include - -class tst_QGLThreads : public QObject -{ -Q_OBJECT -public: - explicit tst_QGLThreads(QObject *parent = 0); - -private slots: - void swapInThread(); - void textureUploadInThread(); - - void renderInThread_data(); - void renderInThread(); - void painterOnGLWidgetInThread(); - void painterOnPixmapInThread(); - void painterOnPboInThread(); - void painterOnFboInThread(); -}; - -#endif // TST_QGLTHREADS_H -- cgit v1.2.3