/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia 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. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include class tst_QOpenGLWindow : public QObject { Q_OBJECT private slots: void create(); void basic(); void painter(); void partial_data(); void partial(); void underOver(); }; void tst_QOpenGLWindow::create() { QOpenGLWindow w; QVERIFY(!w.isValid()); w.resize(640, 480); w.show(); QTest::qWaitForWindowExposed(&w); QVERIFY(w.isValid()); } class Window : public QOpenGLWindow { public: void reset() { initCount = resizeCount = paintCount = 0; } void initializeGL() Q_DECL_OVERRIDE { ++initCount; } void resizeGL(int w, int h) Q_DECL_OVERRIDE { ++resizeCount; QCOMPARE(w, size().width()); QCOMPARE(h, size().height()); } void paintGL() Q_DECL_OVERRIDE { ++paintCount; QOpenGLContext *ctx = QOpenGLContext::currentContext(); QVERIFY(ctx); QCOMPARE(ctx, context()); QOpenGLFunctions *f = ctx->functions(); QVERIFY(f); f->glClearColor(1, 0, 0, 1); f->glClear(GL_COLOR_BUFFER_BIT); img = grabFramebuffer(); } int initCount; int resizeCount; int paintCount; QImage img; }; void tst_QOpenGLWindow::basic() { Window w; w.reset(); w.resize(640, 480); w.show(); QTest::qWaitForWindowExposed(&w); // Check that the virtuals are invoked. QCOMPARE(w.initCount, 1); int resCount = w.resizeCount; QVERIFY(resCount >= 1); QVERIFY(w.paintCount >= 1); // Check that something has been drawn; QCOMPARE(w.img.size(), w.size()); QVERIFY(w.img.pixel(5, 5) == qRgb(255, 0, 0)); // Check that the viewport was properly set. w.makeCurrent(); GLint v[4] = { 0, 0, 0, 0 }; w.context()->functions()->glGetIntegerv(GL_VIEWPORT, v); QCOMPARE(v[0], 0); QCOMPARE(v[1], 0); QCOMPARE(v[2], GLint(w.width() * w.devicePixelRatio())); QCOMPARE(v[3], GLint(w.height() * w.devicePixelRatio())); w.doneCurrent(); // Check that a future resize triggers resizeGL. w.resize(800, 600); int maxWait = 1000; while (w.resizeCount == resCount && maxWait-- >= 0) QTest::qWait(10); QVERIFY(w.resizeCount > resCount); } class PainterWindow : public QOpenGLWindow { public: void paintGL() Q_DECL_OVERRIDE { QOpenGLContext *ctx = QOpenGLContext::currentContext(); QVERIFY(ctx); QCOMPARE(ctx, context()); QOpenGLFunctions *f = ctx->functions(); QVERIFY(f); QPainter p(this); p.beginNativePainting(); f->glClearColor(1, 0, 0, 1); f->glClear(GL_COLOR_BUFFER_BIT); p.endNativePainting(); p.fillRect(QRect(0, 0, 100, 100), Qt::blue); p.end(); img = grabFramebuffer(); } QImage img; }; void tst_QOpenGLWindow::painter() { PainterWindow w; w.resize(400, 400); w.show(); QTest::qWaitForWindowExposed(&w); QCOMPARE(w.img.size(), w.size()); QVERIFY(w.img.pixel(5, 5) == qRgb(0, 0, 255)); QVERIFY(w.img.pixel(200, 5) == qRgb(255, 0, 0)); } class PartialPainterWindow : public QOpenGLWindow { public: PartialPainterWindow(QOpenGLWindow::UpdateBehavior u) : QOpenGLWindow(u), x(0) { } void paintGL() Q_DECL_OVERRIDE { ++paintCount; QPainter p(this); if (!x) p.fillRect(QRect(0, 0, width(), height()), Qt::green); p.fillRect(QRect(x, 0, 10, 10), Qt::blue); x += 20; } int paintCount; int x; }; void tst_QOpenGLWindow::partial_data() { QTest::addColumn("behavior"); QTest::newRow("blit") << int(QOpenGLWindow::PartialUpdateBlit); QTest::newRow("blend") << int(QOpenGLWindow::PartialUpdateBlend); } void tst_QOpenGLWindow::partial() { QFETCH(int, behavior); QOpenGLWindow::UpdateBehavior u = QOpenGLWindow::UpdateBehavior(behavior); PartialPainterWindow w(u); w.resize(800, 400); w.show(); QTest::qWaitForWindowExposed(&w); // Add a couple of small blue rects. for (int i = 0; i < 10; ++i) { w.paintCount = 0; w.update(); int maxWait = 1000; while (w.paintCount == 0 && maxWait-- >= 0) QTest::qWait(10); } // Now since the painting went to an extra framebuffer, all the rects should // be present since everything is preserved between the frames. QImage img = w.grabFramebuffer(); QCOMPARE(img.size(), w.size()); QCOMPARE(img.pixel(5, 5), qRgb(0, 0, 255)); QCOMPARE(img.pixel(15, 5), qRgb(0, 255, 0)); QCOMPARE(img.pixel(25, 5), qRgb(0, 0, 255)); } class PaintUnderOverWindow : public QOpenGLWindow { public: PaintUnderOverWindow() : QOpenGLWindow(PartialUpdateBlend), m_state(None) { } enum State { None, PaintUnder, Paint, PaintOver, Error } m_state; void paintUnderGL() Q_DECL_OVERRIDE { if (m_state == None || m_state == PaintOver) m_state = PaintUnder; else m_state = Error; GLuint fbo = 0xFFFF; QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &fbo); QVERIFY(fbo == 0); } void paintGL() Q_DECL_OVERRIDE { if (m_state == PaintUnder) m_state = Paint; else m_state = Error; // Using PartialUpdateBlend so paintGL() targets a user fbo, not the default. GLuint fbo = 0xFFFF; QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &fbo); QVERIFY(fbo != 0); QCOMPARE(fbo, defaultFramebufferObject()); } void paintOverGL() Q_DECL_OVERRIDE { if (m_state == Paint) m_state = PaintOver; else m_state = Error; GLuint fbo = 0xFFFF; QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &fbo); QVERIFY(fbo == 0); } }; void tst_QOpenGLWindow::underOver() { PaintUnderOverWindow w; w.resize(400, 400); w.show(); QTest::qWaitForWindowExposed(&w); // under -> paint -> over -> under -> paint -> ... is the only acceptable sequence QCOMPARE(w.m_state, PaintUnderOverWindow::PaintOver); } #include QTEST_MAIN(tst_QOpenGLWindow)