// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include #include #include #include "testrenderer.h" #include class DummyTexture : public Qt3DRender::QAbstractTexture { Q_OBJECT public: explicit DummyTexture(Qt3DCore::QNode *parent = nullptr) : QAbstractTexture(TargetAutomatic, parent) { } }; class FakeGenerator : public Qt3DRender::QTextureGenerator { public: QT3D_FUNCTOR(FakeGenerator) Qt3DRender::QTextureDataPtr operator ()() override { return {}; } bool operator ==(const QTextureGenerator &) const override { return true; } }; class tst_RenderTexture : public Qt3DCore::QBackendNodeTester { Q_OBJECT private: template void checkPropertyMirroring(); private slots: void checkDefaults(); void checkFrontendPropertyNotifications(); void checkPropertyMirroring(); void checkPropertyChanges(); void checkTextureImageBookeeping(); void checkInitialUpdateData(); }; void tst_RenderTexture::checkDefaults() { Qt3DRender::Render::Texture backend; QCOMPARE(backend.properties().format, Qt3DRender::QAbstractTexture::NoFormat); QCOMPARE(backend.properties().width, 1); QCOMPARE(backend.properties().height, 1); QCOMPARE(backend.properties().depth, 1); QCOMPARE(backend.properties().layers, 1); QCOMPARE(backend.properties().mipLevels, 1); QCOMPARE(backend.properties().samples, 1); QCOMPARE(backend.properties().generateMipMaps, false); QCOMPARE(backend.parameters().magnificationFilter, Qt3DRender::QAbstractTexture::Nearest); QCOMPARE(backend.parameters().minificationFilter, Qt3DRender::QAbstractTexture::Nearest); QCOMPARE(backend.parameters().wrapModeX, Qt3DRender::QTextureWrapMode::ClampToEdge); QCOMPARE(backend.parameters().wrapModeY, Qt3DRender::QTextureWrapMode::ClampToEdge); QCOMPARE(backend.parameters().wrapModeZ, Qt3DRender::QTextureWrapMode::ClampToEdge); QCOMPARE(backend.parameters().maximumAnisotropy, 1.0f); QCOMPARE(backend.parameters().comparisonFunction, Qt3DRender::QAbstractTexture::CompareLessEqual); QCOMPARE(backend.parameters().comparisonMode, Qt3DRender::QAbstractTexture::CompareNone); } void tst_RenderTexture::checkFrontendPropertyNotifications() { // GIVEN TestArbiter arbiter; DummyTexture texture; arbiter.setArbiterOnNode(&texture); // WHEN texture.setWidth(512); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.setWidth(512); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 0); // WHEN texture.setHeight(256); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.setHeight(256); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 0); // WHEN texture.setDepth(128); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.setDepth(128); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 0); // WHEN texture.setLayers(16); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.setLayers(16); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 0); // WHEN texture.setSamples(32); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.setSamples(32); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 0); // WHEN Qt3DRender::QTextureImage img; texture.addTextureImage(&img); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); // WHEN texture.removeTextureImage(&img); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), &texture); arbiter.clear(); } template void tst_RenderTexture::checkPropertyMirroring() { // GIVEN Qt3DRender::Render::Texture backend; FrontendTextureType frontend; frontend.setWidth(256); frontend.setHeight(128); frontend.setDepth(16); frontend.setLayers(8); frontend.setSamples(32); frontend.setMipLevels(8); // WHEN simulateInitializationSync(&frontend, &backend); // THEN QCOMPARE(backend.peerId(), frontend.id()); QCOMPARE(backend.properties().target, Target); QCOMPARE(backend.properties().width, frontend.width()); QCOMPARE(backend.properties().height, frontend.height()); QCOMPARE(backend.properties().depth, frontend.depth()); QCOMPARE(backend.properties().layers, frontend.layers()); QCOMPARE(backend.properties().samples, frontend.samples()); } void tst_RenderTexture::checkPropertyMirroring() { checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); checkPropertyMirroring(); } void tst_RenderTexture::checkPropertyChanges() { // GIVEN TestRenderer renderer; Qt3DRender::QSharedGLTexture frontend; Qt3DRender::Render::Texture backend; backend.setRenderer(&renderer); backend.unsetDirty(); // WHEN frontend.setWidth(256); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().width, 256); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setHeight(128); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().height, 128); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setDepth(16); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().depth, 16); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setFormat(Qt3DRender::QAbstractTexture::RGB16F); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().format, Qt3DRender::QAbstractTexture::RGB16F); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setGenerateMipMaps(true); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().generateMipMaps, true); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setMinificationFilter(Qt3DRender::QAbstractTexture::LinearMipMapLinear); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().minificationFilter, Qt3DRender::QAbstractTexture::LinearMipMapLinear); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().magnificationFilter, Qt3DRender::QAbstractTexture::Linear); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.wrapMode()->setX(Qt3DRender::QTextureWrapMode::Repeat); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().wrapModeX, Qt3DRender::QTextureWrapMode::Repeat); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.wrapMode()->setY(Qt3DRender::QTextureWrapMode::Repeat); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().wrapModeY, Qt3DRender::QTextureWrapMode::Repeat); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.wrapMode()->setZ(Qt3DRender::QTextureWrapMode::Repeat); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().wrapModeZ, Qt3DRender::QTextureWrapMode::Repeat); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setMaximumAnisotropy(16.f); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().maximumAnisotropy, 16.0f); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setComparisonFunction(Qt3DRender::QAbstractTexture::CompareEqual); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().comparisonFunction, Qt3DRender::QAbstractTexture::CompareEqual); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setComparisonMode(Qt3DRender::QAbstractTexture::CompareRefToTexture); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.parameters().comparisonMode, Qt3DRender::QAbstractTexture::CompareRefToTexture); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyParameters); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setLayers(32); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().layers, 32); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setSamples(64); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.properties().samples, 64); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyProperties); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN frontend.setTextureId(883); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.sharedTextureId(), 883); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtySharedTextureId); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN Qt3DRender::QTextureImage img; frontend.addTextureImage(&img); backend.syncFromFrontEnd(&frontend, false); // THEN QCOMPARE(backend.textureImageIds().size(), 1); QCOMPARE(backend.textureImageIds().first(), img.id()); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyImageGenerators); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); // WHEN Qt3DRender::QTextureDataUpdate updateData; updateData.setX(100); updateData.setY(100); updateData.setZ(100); frontend.updateData(updateData); backend.syncFromFrontEnd(&frontend, false); // THEN const std::vector pendingUpdates = backend.takePendingTextureDataUpdates(); QCOMPARE(pendingUpdates.size(), 1U); QCOMPARE(pendingUpdates.front(), updateData); QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty); QVERIFY(backend.dirtyFlags() == Qt3DRender::Render::Texture::DirtyPendingDataUpdates); renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); backend.unsetDirty(); } void tst_RenderTexture::checkTextureImageBookeeping() { // GIVEN TestArbiter arbiter; DummyTexture texture; arbiter.setArbiterOnNode(&texture); QCoreApplication::processEvents(); { // WHEN Qt3DRender::QTextureImage img; texture.addTextureImage(&img); // THEN QCOMPARE(img.parent(), &texture); QCOMPARE(texture.textureImages().size(), 1); QCOMPARE(texture.textureImages().first()->id(), img.id()); } // WHEN -> img is destroyed // THEN QCOMPARE(texture.textureImages().size(), 0); } void tst_RenderTexture::checkInitialUpdateData() { // GIVEN TestRenderer renderer; DummyTexture frontend; Qt3DRender::Render::Texture backend; backend.setRenderer(&renderer); Qt3DRender::QTextureDataUpdate updateData; updateData.setX(100); updateData.setY(100); updateData.setZ(100); // WHEN -> updateData with no backend/arbiter frontend.updateData(updateData); simulateInitializationSync(&frontend, &backend); // THEN -> should have received the update as part of the initial data const std::vector pendingUpdates = backend.takePendingTextureDataUpdates(); QCOMPARE(pendingUpdates.size(), 1U); QCOMPARE(pendingUpdates.front(), updateData); QVERIFY(backend.dirtyFlags() & Qt3DRender::Render::Texture::DirtyPendingDataUpdates); } QTEST_APPLESS_MAIN(tst_RenderTexture) #include "tst_texture.moc"