diff options
Diffstat (limited to 'tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp')
-rw-r--r-- | tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp b/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp new file mode 100644 index 0000000000..4bab4e345a --- /dev/null +++ b/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#if QT_CONFIG(opengl) +#include <QOffscreenSurface> +#include <QOpenGLContext> +#include <QOpenGLFunctions> +#include <QOpenGLFramebufferObject> +#endif +#include <QAnimationDriver> + +#include <QQuickWindow> +#include <QQuickRenderControl> +#include <QQuickItem> +#include <QQmlEngine> +#include <QQmlComponent> + +#include "../../shared/util.h" + +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> + +class tst_RenderControl : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void initTestCase(); + void renderAndReadBack(); +}; + +void tst_RenderControl::initTestCase() +{ + QQmlDataTest::initTestCase(); +} + +class AnimationDriver : public QAnimationDriver +{ +public: + AnimationDriver(int msPerStep) : m_step(msPerStep) { } + + void advance() override + { + m_elapsed += m_step; + advanceAnimation(); + } + + qint64 elapsed() const override + { + return m_elapsed; + } + +private: + int m_step; + qint64 m_elapsed = 0; +}; + + +void tst_RenderControl::renderAndReadBack() +{ + static const int ANIM_ADVANCE_PER_FRAME = 16; // milliseconds + QScopedPointer<AnimationDriver> animDriver(new AnimationDriver(ANIM_ADVANCE_PER_FRAME)); + animDriver->install(); + + // ### Qt 6: migrate this to OpenGL-on-RHI +#if QT_CONFIG(opengl) + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + QSKIP("Skipping due to platform not supporting OpenGL at run time"); + + QScopedPointer<QOpenGLContext> context(new QOpenGLContext); + QVERIFY(context->create()); + QScopedPointer<QOffscreenSurface> offscreenSurface(new QOffscreenSurface); + offscreenSurface->setFormat(context->format()); + offscreenSurface->create(); + QVERIFY(context->makeCurrent(offscreenSurface.data())); + + QScopedPointer<QQuickRenderControl> renderControl(new QQuickRenderControl); + QScopedPointer<QQuickWindow> quickWindow(new QQuickWindow(renderControl.data())); + QScopedPointer<QQmlEngine> qmlEngine(new QQmlEngine); + + QScopedPointer<QQmlComponent> qmlComponent(new QQmlComponent(qmlEngine.data(), testFileUrl(QLatin1String("rect.qml")))); + QVERIFY(!qmlComponent->isLoading()); + if (qmlComponent->isError()) { + for (const QQmlError &error : qmlComponent->errors()) + qWarning() << error.url() << error.line() << error; + } + QVERIFY(!qmlComponent->isError()); + + QObject *rootObject = qmlComponent->create(); + if (qmlComponent->isError()) { + for (const QQmlError &error : qmlComponent->errors()) + qWarning() << error.url() << error.line() << error; + } + QVERIFY(!qmlComponent->isError()); + + QQuickItem *rootItem = qobject_cast<QQuickItem *>(rootObject); + QVERIFY(rootItem); + QCOMPARE(rootItem->size(), QSize(200, 200)); + + quickWindow->contentItem()->setSize(rootItem->size()); + quickWindow->setGeometry(0, 0, rootItem->width(), rootItem->height()); + + rootItem->setParentItem(quickWindow->contentItem()); + + renderControl->initialize(context.data()); + + // cannot do this test with the 'software' backend of Qt Quick + QSGRendererInterface::GraphicsApi api = quickWindow->rendererInterface()->graphicsApi(); + if (api != QSGRendererInterface::OpenGL) + QSKIP("Skipping due to Qt Quick not using the direct OpenGL rendering path"); + + QScopedPointer<QOpenGLFramebufferObject> fbo(new QOpenGLFramebufferObject(rootItem->size().toSize(), + QOpenGLFramebufferObject::CombinedDepthStencil)); + + quickWindow->setRenderTarget(fbo.data()); + + for (int frame = 0; frame < 100; ++frame) { + // have to process events, e.g. to get queued metacalls delivered + QCoreApplication::processEvents(); + + if (frame > 0) { + // Quick animations will now think that ANIM_ADVANCE_PER_FRAME milliseconds have passed, + // even though in reality we have a tight loop that generates frames unthrottled. + animDriver->advance(); + } + + renderControl->polishItems(); + renderControl->sync(); + renderControl->render(); + + context->functions()->glFlush(); + + QImage img = fbo->toImage(); + QVERIFY(!img.isNull()); + QCOMPARE(img.size(), rootItem->size()); + + const int maxFuzz = 2; + + // The scene is: background, rectangle, text + // where rectangle rotates + + QRgb background = img.pixel(5, 5); + QVERIFY(qAbs(qRed(background) - 70) < maxFuzz); + QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz); + QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz); + + background = img.pixel(195, 195); + QVERIFY(qAbs(qRed(background) - 70) < maxFuzz); + QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz); + QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz); + + // after about 1.25 seconds (animation time, one iteration is 16 ms + // thanks to our custom animation driver) the rectangle reaches a 90 + // degree rotation, that should be frame 76 + if (frame <= 2 || (frame >= 76 && frame <= 80)) { + QRgb c = img.pixel(28, 28); // rectangle + QVERIFY(qAbs(qRed(c) - 152) < maxFuzz); + QVERIFY(qAbs(qGreen(c) - 251) < maxFuzz); + QVERIFY(qAbs(qBlue(c) - 152) < maxFuzz); + } else { + QRgb c = img.pixel(28, 28); // background because rectangle got rotated so this pixel is not covered by it + QVERIFY(qAbs(qRed(c) - 70) < maxFuzz); + QVERIFY(qAbs(qGreen(c) - 130) < maxFuzz); + QVERIFY(qAbs(qBlue(c) - 180) < maxFuzz); + } + } + +#else + QSKIP("No OpenGL, skipping rendercontrol test"); +#endif +} + +#include "tst_qquickrendercontrol.moc" + +QTEST_MAIN(tst_RenderControl) |