Revision control
++ // Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++
++ #include <QtTest/QTest>
++ #include <Qt3DRender/qtechnique.h>
++ #include <Qt3DRender/qfilterkey.h>
++ #include <Qt3DRender/qparameter.h>
++ #include <Qt3DRender/qrenderpass.h>
++ #include <Qt3DRender/private/qtechnique_p.h>
++ #include <Qt3DRender/private/technique_p.h>
++ #include <Qt3DRender/private/nodemanagers_p.h>
++ #include <Qt3DRender/private/managers_p.h>
++ #include <Qt3DRender/private/filterkey_p.h>
++ #include <Qt3DRender/private/techniquemanager_p.h>
++ #include "qbackendnodetester.h"
++ #include "testrenderer.h"
++
++ class tst_Technique : public Qt3DCore::QBackendNodeTester
++ {
++ Q_OBJECT
++
++ private Q_SLOTS:
++
++ void checkInitialState()
++ {
++ // GIVEN
++ Qt3DRender::Render::Technique backendTechnique;
++
++ // THEN
++ QCOMPARE(backendTechnique.isEnabled(), false);
++ QVERIFY(backendTechnique.peerId().isNull());
++
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_minor, 0);
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_major, 0);
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_profile, Qt3DRender::QGraphicsApiFilter::NoProfile);
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_vendor, QString());
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_extensions, QStringList());
++
++ QCOMPARE(backendTechnique.parameters().size(), 0);
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ QCOMPARE(backendTechnique.renderPasses().size(), 0);
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
++ QVERIFY(backendTechnique.nodeManager() == nullptr);
++ }
++
++ void checkCleanupState()
++ {
++ // GIVEN
++ TestRenderer renderer;
++ Qt3DRender::Render::Technique backendTechnique;
++ Qt3DRender::Render::NodeManagers nodeManagers;
++
++ // WHEN
++ backendTechnique.setRenderer(&renderer);
++ backendTechnique.setEnabled(true);
++ backendTechnique.setNodeManager(&nodeManagers);
++ backendTechnique.setCompatibleWithRenderer(true);
++
++ {
++ Qt3DRender::QTechnique technique;
++ Qt3DRender::QRenderPass pass;
++ Qt3DRender::QParameter parameter;
++ Qt3DRender::QFilterKey filterKey;
++
++ technique.addRenderPass(&pass);
++ technique.addParameter(¶meter);
++ technique.addFilterKey(&filterKey);
++
++ simulateInitializationSync(&technique, &backendTechnique);
++ }
++
++ backendTechnique.cleanup();
++
++ // THEN
++ QCOMPARE(backendTechnique.isEnabled(), false);
++ QCOMPARE(backendTechnique.parameters().size(), 0);
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ QCOMPARE(backendTechnique.renderPasses().size(), 0);
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
++ }
++
++ void checkInitializeFromPeer()
++ {
++ // GIVEN
++ TestRenderer renderer;
++ Qt3DRender::QTechnique technique;
++ Qt3DRender::QRenderPass pass;
++ Qt3DRender::QParameter parameter;
++ Qt3DRender::QFilterKey filterKey;
++
++ technique.addRenderPass(&pass);
++ technique.addParameter(¶meter);
++ technique.addFilterKey(&filterKey);
++
++ {
++ // WHEN
++ Qt3DRender::Render::Technique backendTechnique;
++ Qt3DRender::Render::NodeManagers nodeManagers;
++
++ backendTechnique.setRenderer(&renderer);
++ backendTechnique.setNodeManager(&nodeManagers);
++ simulateInitializationSync(&technique, &backendTechnique);
++
++ // THEN
++ QCOMPARE(backendTechnique.isEnabled(), true);
++ QCOMPARE(backendTechnique.peerId(), technique.id());
++ Qt3DRender::GraphicsApiFilterData apiFilterData = Qt3DRender::QGraphicsApiFilterPrivate::get(technique.graphicsApiFilter())->m_data;
++ QCOMPARE(*backendTechnique.graphicsApiFilter(), apiFilterData);
++ QCOMPARE(backendTechnique.parameters().size(), 1);
++ QCOMPARE(backendTechnique.parameters().first(), parameter.id());
++ QCOMPARE(backendTechnique.filterKeys().size(), 1);
++ QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
++ QCOMPARE(backendTechnique.renderPasses().size(), 1);
++ QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
++ const std::vector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
++ QCOMPARE(dirtyTechniques.size(), 1U);
++ QCOMPARE(dirtyTechniques.front(), backendTechnique.peerId());
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ }
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ {
++ // WHEN
++ Qt3DRender::Render::Technique backendTechnique;
++ Qt3DRender::Render::NodeManagers nodeManagers;
++
++ backendTechnique.setNodeManager(&nodeManagers);
++ backendTechnique.setRenderer(&renderer);
++ technique.setEnabled(false);
++ simulateInitializationSync(&technique, &backendTechnique);
++
++ // THEN
++ QCOMPARE(backendTechnique.peerId(), technique.id());
++ QCOMPARE(backendTechnique.isEnabled(), false);
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ }
++ }
++
++ void checkSetCompatibleWithRenderer()
++ {
++ // GIVEN
++ Qt3DRender::Render::Technique backendTechnique;
++
++ // THEN
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
++
++ // WHEN
++ backendTechnique.setCompatibleWithRenderer(true);
++
++ // THEN
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), true);
++ }
++
++ void checkSceneChangeEvents()
++ {
++ // GIVEN
++ Qt3DRender::QTechnique technique;
++ Qt3DRender::Render::Technique backendTechnique;
++ Qt3DRender::Render::NodeManagers nodeManagers;
++
++ TestRenderer renderer;
++ backendTechnique.setRenderer(&renderer);
++ backendTechnique.setNodeManager(&nodeManagers);
++
++ {
++ // WHEN
++ const bool newValue = true;
++ technique.setEnabled(newValue);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.isEnabled(), newValue);
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ QCOMPARE(nodeManagers.techniqueManager()->takeDirtyTechniques().size(), 1U);
++ }
++ {
++ // WHEN
++ backendTechnique.setCompatibleWithRenderer(true);
++ QCOMPARE(nodeManagers.techniqueManager()->takeDirtyTechniques().size(), 0U);
++
++ technique.graphicsApiFilter()->setMajorVersion(4);
++ technique.graphicsApiFilter()->setMinorVersion(5);
++ technique.graphicsApiFilter()->setVendor(QStringLiteral("ATI"));
++
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_major, technique.graphicsApiFilter()->majorVersion());
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_minor, technique.graphicsApiFilter()->minorVersion());
++ QCOMPARE(backendTechnique.graphicsApiFilter()->m_vendor, technique.graphicsApiFilter()->vendor());
++ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
++
++ const std::vector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
++ QCOMPARE(dirtyTechniques.size(), 1U);
++ QCOMPARE(dirtyTechniques.front(), backendTechnique.peerId());
++
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ {
++ Qt3DRender::QParameter parameter;
++
++ {
++ // WHEN
++ technique.addParameter(¶meter);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.parameters().size(), 1);
++ QCOMPARE(backendTechnique.parameters().first(), parameter.id());
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ {
++ // WHEN
++ technique.removeParameter(¶meter);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.parameters().size(), 0);
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ }
++ {
++ Qt3DRender::QFilterKey filterKey;
++
++ {
++ // WHEN
++ technique.addFilterKey(&filterKey);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 1);
++ QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ {
++ // WHEN
++ technique.removeFilterKey(&filterKey);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ }
++ {
++ Qt3DRender::QRenderPass pass;
++
++ {
++ // WHEN
++ technique.addRenderPass(&pass);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.renderPasses().size(), 1);
++ QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ {
++ // WHEN
++ technique.removeRenderPass(&pass);
++ backendTechnique.syncFromFrontEnd(&technique, false);
++
++ // THEN
++ QCOMPARE(backendTechnique.renderPasses().size(), 0);
++ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
++ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
++ }
++ }
++ }
++
++ void checkIsCompatibleWithFilters()
++ {
++ // GIVEN
++ TestRenderer renderer;
++ Qt3DRender::Render::Technique backendTechnique;
++ Qt3DRender::Render::NodeManagers nodeManagers;
++
++ backendTechnique.setNodeManager(&nodeManagers);
++
++ Qt3DRender::QFilterKey *filterKey1 = new Qt3DRender::QFilterKey();
++ Qt3DRender::QFilterKey *filterKey2 = new Qt3DRender::QFilterKey();
++ Qt3DRender::QFilterKey *filterKey3 = new Qt3DRender::QFilterKey();
++ Qt3DRender::QFilterKey *filterKey4 = new Qt3DRender::QFilterKey();
++ Qt3DRender::QFilterKey *filterKey5 = new Qt3DRender::QFilterKey();
++
++ filterKey1->setName(QStringLiteral("displacement"));
++ filterKey2->setName(QStringLiteral("diffRatio"));
++ filterKey3->setName(QStringLiteral("oil"));
++ filterKey4->setName(QStringLiteral("oil"));
++ filterKey5->setName(QStringLiteral("heads"));
++
++ filterKey1->setValue(QVariant(427.0f));
++ filterKey2->setValue(QVariant(4.11f));
++ filterKey3->setValue(QVariant(QStringLiteral("Valvoline-VR1")));
++ filterKey4->setValue(QVariant(QStringLiteral("Mobil-1")));
++ filterKey5->setName(QStringLiteral("AFR"));
++
++ // Create backend nodes
++ // WHEN
++ Qt3DRender::Render::FilterKey *backendFilterKey1 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey1->id());
++ Qt3DRender::Render::FilterKey *backendFilterKey2 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey2->id());
++ Qt3DRender::Render::FilterKey *backendFilterKey3 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey3->id());
++ Qt3DRender::Render::FilterKey *backendFilterKey4 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey4->id());
++ Qt3DRender::Render::FilterKey *backendFilterKey5 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey5->id());
++
++ backendFilterKey1->setRenderer(&renderer);
++ backendFilterKey2->setRenderer(&renderer);
++ backendFilterKey3->setRenderer(&renderer);
++ backendFilterKey4->setRenderer(&renderer);
++ backendFilterKey5->setRenderer(&renderer);
++
++ simulateInitializationSync(filterKey1, backendFilterKey1);
++ simulateInitializationSync(filterKey2, backendFilterKey2);
++ simulateInitializationSync(filterKey3, backendFilterKey3);
++ simulateInitializationSync(filterKey4, backendFilterKey4);
++ simulateInitializationSync(filterKey5, backendFilterKey5);
++
++ // THEN
++ QCOMPARE(nodeManagers.filterKeyManager()->activeHandles().size(), size_t(5));
++
++ {
++ // WHEN
++ backendTechnique.appendFilterKey(filterKey1->id());
++ backendTechnique.appendFilterKey(filterKey2->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 2);
++
++ // WHEN
++ Qt3DCore::QNodeIdVector techniqueFilters;
++ techniqueFilters.push_back(filterKey1->id());
++ techniqueFilters.push_back(filterKey2->id());
++ techniqueFilters.push_back(filterKey3->id());
++ techniqueFilters.push_back(filterKey5->id());
++
++ // THEN -> incompatible technique doesn't have enough filters
++ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
++
++ // WHEN
++ backendTechnique.removeFilterKey(filterKey1->id());
++ backendTechnique.removeFilterKey(filterKey2->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ }
++
++ {
++ // WHEN
++ backendTechnique.appendFilterKey(filterKey1->id());
++ backendTechnique.appendFilterKey(filterKey2->id());
++ backendTechnique.appendFilterKey(filterKey3->id());
++ backendTechnique.appendFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 4);
++
++ // WHEN
++ Qt3DCore::QNodeIdVector techniqueFilters;
++ techniqueFilters.push_back(filterKey1->id());
++ techniqueFilters.push_back(filterKey2->id());
++ techniqueFilters.push_back(filterKey3->id());
++ techniqueFilters.push_back(filterKey5->id());
++
++ // THEN -> compatible same number
++ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
++
++ // WHEN
++ backendTechnique.removeFilterKey(filterKey1->id());
++ backendTechnique.removeFilterKey(filterKey2->id());
++ backendTechnique.removeFilterKey(filterKey3->id());
++ backendTechnique.removeFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ }
++
++ {
++ // WHEN
++ backendTechnique.appendFilterKey(filterKey1->id());
++ backendTechnique.appendFilterKey(filterKey2->id());
++ backendTechnique.appendFilterKey(filterKey3->id());
++ backendTechnique.appendFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 4);
++
++ // WHEN
++ Qt3DCore::QNodeIdVector techniqueFilters;
++ techniqueFilters.push_back(filterKey1->id());
++ techniqueFilters.push_back(filterKey2->id());
++ techniqueFilters.push_back(filterKey4->id());
++ techniqueFilters.push_back(filterKey5->id());
++
++ // THEN -> compatible same number, one not matching
++ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
++
++ // WHEN
++ backendTechnique.removeFilterKey(filterKey1->id());
++ backendTechnique.removeFilterKey(filterKey2->id());
++ backendTechnique.removeFilterKey(filterKey3->id());
++ backendTechnique.removeFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ }
++
++ {
++ // WHEN
++ backendTechnique.appendFilterKey(filterKey1->id());
++ backendTechnique.appendFilterKey(filterKey2->id());
++ backendTechnique.appendFilterKey(filterKey3->id());
++ backendTechnique.appendFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 4);
++
++ // WHEN
++ Qt3DCore::QNodeIdVector techniqueFilters;
++ techniqueFilters.push_back(filterKey1->id());
++ techniqueFilters.push_back(filterKey2->id());
++ techniqueFilters.push_back(filterKey3->id());
++
++ // THEN -> technique has more than necessary filters
++ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
++
++ // WHEN
++ backendTechnique.removeFilterKey(filterKey1->id());
++ backendTechnique.removeFilterKey(filterKey2->id());
++ backendTechnique.removeFilterKey(filterKey3->id());
++ backendTechnique.removeFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ }
++
++ {
++ // WHEN
++ backendTechnique.appendFilterKey(filterKey1->id());
++ backendTechnique.appendFilterKey(filterKey2->id());
++ backendTechnique.appendFilterKey(filterKey3->id());
++ backendTechnique.appendFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 4);
++
++ // WHEN
++ Qt3DCore::QNodeIdVector techniqueFilters;
++ techniqueFilters.push_back(filterKey1->id());
++ techniqueFilters.push_back(filterKey2->id());
++ techniqueFilters.push_back(filterKey4->id());
++
++ // THEN -> technique has more than necessary filters
++ // but one is not matching
++ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
++
++ // WHEN
++ backendTechnique.removeFilterKey(filterKey1->id());
++ backendTechnique.removeFilterKey(filterKey2->id());
++ backendTechnique.removeFilterKey(filterKey3->id());
++ backendTechnique.removeFilterKey(filterKey5->id());
++
++ // THEN
++ QCOMPARE(backendTechnique.filterKeys().size(), 0);
++ }
++ }
++ };
++
++ QTEST_MAIN(tst_Technique)
++
++ #include "tst_technique.moc"