blob: 7a08fe01842819952674326b9aa90fdee1e97f95 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module 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 <QtTest/QTest>
#include <qbackendnodetester.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qbackendnode_p.h>
#include <Qt3DRender/private/shaderbuilder_p.h>
#include <Qt3DRender/qshaderprogram.h>
#include <Qt3DRender/qshaderprogrambuilder.h>
#include "testrenderer.h"
#include "testpostmanarbiter.h"
Q_DECLARE_METATYPE(Qt3DRender::QShaderProgram::ShaderType)
class tst_ShaderBuilder : public Qt3DCore::QBackendNodeTester
{
Q_OBJECT
private slots:
void shouldHaveGlobalDefaultPrototypes()
{
// GIVEN
// THEN
QCOMPARE(Qt3DRender::Render::ShaderBuilder::getPrototypesFile(), QStringLiteral(":/prototypes/default.json"));
QVERIFY(!Qt3DRender::Render::ShaderBuilder::getPrototypeNames().isEmpty());
// WHEN
Qt3DRender::Render::ShaderBuilder::setPrototypesFile(":/prototypes.json");
// THEN
QCOMPARE(Qt3DRender::Render::ShaderBuilder::getPrototypesFile(), QStringLiteral(":/prototypes.json"));
auto prototypeNames = Qt3DRender::Render::ShaderBuilder::getPrototypeNames();
prototypeNames.sort();
const auto expectedPrototypeNames = QStringList() << "exposure"
<< "exposureFunction"
<< "fragColor"
<< "lightIntensity"
<< "lightModel"
<< "sampleTexture"
<< "texCoord"
<< "texture"
<< "worldPosition";
QCOMPARE(prototypeNames, expectedPrototypeNames);
}
void shouldHaveInitialState()
{
// GIVEN
Qt3DRender::Render::ShaderBuilder shaderBuilder;
// THEN
QVERIFY(!shaderBuilder.isEnabled());
QVERIFY(shaderBuilder.enabledLayers().isEmpty());
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QCOMPARE(shaderBuilder.shaderGraph(type), QUrl());
QCOMPARE(shaderBuilder.shaderCode(type), QByteArray());
QVERIFY(!shaderBuilder.isShaderCodeDirty(type));
}
}
void shouldHavePropertiesMirroringFromItsPeer_data()
{
QTest::addColumn<Qt3DRender::QShaderProgramBuilder*>("frontend");
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
QTest::newRow("empty") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
auto program = new Qt3DRender::QShaderProgram(frontend);
frontend->setShaderProgram(program);
QTest::newRow("shaderProgram") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setEnabledLayers({"foo", "bar"});
QTest::newRow("enabledLayers") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setVertexShaderGraph(QUrl::fromEncoded("qrc:/vertex.json"));
QTest::newRow("vertex") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setTessellationControlShaderGraph(QUrl::fromEncoded("qrc:/tesscontrol.json"));
QTest::newRow("tessellationControl") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setTessellationEvaluationShaderGraph(QUrl::fromEncoded("qrc:/tesseval.json"));
QTest::newRow("tessellationEvaluation") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setGeometryShaderGraph(QUrl::fromEncoded("qrc:/geometry.json"));
QTest::newRow("geometry") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setFragmentShaderGraph(QUrl::fromEncoded("qrc:/fragment.json"));
QTest::newRow("fragment") << frontend;
}
{
auto frontend = new Qt3DRender::QShaderProgramBuilder;
frontend->setComputeShaderGraph(QUrl::fromEncoded("qrc:/compute.json"));
QTest::newRow("compute") << frontend;
}
}
void shouldHavePropertiesMirroringFromItsPeer()
{
// GIVEN
QFETCH(Qt3DRender::QShaderProgramBuilder*, frontend);
Qt3DRender::Render::ShaderBuilder backend;
TestRenderer renderer;
// WHEN
backend.setRenderer(&renderer);
simulateInitializationSync(frontend, &backend);
// THEN
QVERIFY(backend.isEnabled() == frontend->isEnabled());
if (frontend->shaderProgram())
QCOMPARE(backend.shaderProgramId(), frontend->shaderProgram()->id());
else
QVERIFY(backend.shaderProgramId().isNull());
QCOMPARE(backend.enabledLayers(), frontend->enabledLayers());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::Vertex), frontend->vertexShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::Vertex), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::Vertex), !frontend->vertexShaderGraph().isEmpty());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::TessellationControl), frontend->tessellationControlShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::TessellationControl), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::TessellationControl), !frontend->tessellationControlShaderGraph().isEmpty());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::TessellationEvaluation), frontend->tessellationEvaluationShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::TessellationEvaluation), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::TessellationEvaluation), !frontend->tessellationEvaluationShaderGraph().isEmpty());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::Geometry), frontend->geometryShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::Geometry), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::Geometry), !frontend->geometryShaderGraph().isEmpty());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::Fragment), frontend->fragmentShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::Fragment), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::Fragment), !frontend->fragmentShaderGraph().isEmpty());
QCOMPARE(backend.shaderGraph(Qt3DRender::QShaderProgram::Compute), frontend->computeShaderGraph());
QCOMPARE(backend.shaderCode(Qt3DRender::QShaderProgram::Compute), QByteArray());
QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::QShaderProgram::Compute), !frontend->computeShaderGraph().isEmpty());
// WHEN
backend.cleanup();
// THEN
QVERIFY(!backend.isEnabled());
QVERIFY(backend.enabledLayers().isEmpty());
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QCOMPARE(backend.shaderGraph(type), QUrl());
QCOMPARE(backend.shaderCode(type), QByteArray());
QVERIFY(!backend.isShaderCodeDirty(type));
}
delete frontend;
}
void shouldHandleEnablePropertyChange()
{
// GIVEN
Qt3DRender::Render::ShaderBuilder backend;
Qt3DRender::QShaderProgramBuilder frontend;
TestRenderer renderer;
backend.setRenderer(&renderer);
simulateInitializationSync(&frontend, &backend);
// WHEN
frontend.setEnabled(false);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QVERIFY(!backend.isEnabled());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
frontend.setEnabled(true);
backend.syncFromFrontEnd(&frontend, false);
// AND
backend.cleanup();
// THEN
QVERIFY(!backend.isEnabled());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
}
void shouldHandleShaderProgramPropertyChange()
{
// GIVEN
Qt3DRender::Render::ShaderBuilder backend;
Qt3DRender::QShaderProgramBuilder frontend;
TestRenderer renderer;
backend.setRenderer(&renderer);
simulateInitializationSync(&frontend, &backend);
// WHEN
Qt3DRender::QShaderProgram prog;
frontend.setShaderProgram(&prog);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.shaderProgramId(), prog.id());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
frontend.setShaderProgram(nullptr);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QVERIFY(backend.shaderProgramId().isNull());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
frontend.setShaderProgram(&prog);
backend.syncFromFrontEnd(&frontend, false);
// AND
backend.cleanup();
// THEN
QVERIFY(backend.shaderProgramId().isNull());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
}
void shouldHandleEnabledLayersPropertyChange()
{
// GIVEN
Qt3DRender::Render::ShaderBuilder backend;
Qt3DRender::QShaderProgramBuilder frontend;
TestRenderer renderer;
backend.setRenderer(&renderer);
simulateInitializationSync(&frontend, &backend);
const auto layers = QStringList() << "foo" << "bar";
static const std::pair<
Qt3DRender::QShaderProgram::ShaderType,
void (Qt3DRender::QShaderProgramBuilder::*)(const QUrl &)
>
shaderTypesToSetters[] = {
{Qt3DRender::QShaderProgram::Vertex, &Qt3DRender::QShaderProgramBuilder::setVertexShaderGraph},
{Qt3DRender::QShaderProgram::TessellationControl, &Qt3DRender::QShaderProgramBuilder::setTessellationControlShaderGraph},
{Qt3DRender::QShaderProgram::TessellationEvaluation, &Qt3DRender::QShaderProgramBuilder::setTessellationEvaluationShaderGraph},
{Qt3DRender::QShaderProgram::Geometry, &Qt3DRender::QShaderProgramBuilder::setGeometryShaderGraph},
{Qt3DRender::QShaderProgram::Fragment, &Qt3DRender::QShaderProgramBuilder::setFragmentShaderGraph},
{Qt3DRender::QShaderProgram::Compute, &Qt3DRender::QShaderProgramBuilder::setComputeShaderGraph},
};
for (auto it = std::begin(shaderTypesToSetters), end = std::end(shaderTypesToSetters); it != end; ++it) {
const auto graphUrl = QUrl::fromEncoded("qrc:/input.json");
(frontend.*(it->second))(graphUrl);
}
// WHEN
frontend.setEnabledLayers(layers);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.enabledLayers(), layers);
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QVERIFY(backend.isShaderCodeDirty(type));
backend.generateCode(type); // Resets the dirty flag
}
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
frontend.setEnabledLayers(layers);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.enabledLayers(), layers);
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QVERIFY(!backend.isShaderCodeDirty(type));
backend.generateCode(type); // Resets the dirty flag
}
QCOMPARE(renderer.dirtyBits(), 0);
renderer.resetDirty();
// WHEN
frontend.setEnabledLayers(QStringList());
backend.syncFromFrontEnd(&frontend, false);
// THEN
QVERIFY(backend.shaderProgramId().isNull());
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QVERIFY(backend.isShaderCodeDirty(type));
backend.generateCode(type); // Resets the dirty flag
}
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
frontend.setEnabledLayers(layers);
backend.syncFromFrontEnd(&frontend, false);
// AND
backend.cleanup();
// THEN
QVERIFY(backend.enabledLayers().isEmpty());
for (int i = 0; i <= Qt3DRender::QShaderProgram::Compute; i++) {
const auto type = static_cast<Qt3DRender::QShaderProgram::ShaderType>(i);
QVERIFY(!backend.isShaderCodeDirty(type));
backend.generateCode(type); // Resets the dirty flag
}
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
}
void shouldHandleShaderGraphPropertiesChanges_data()
{
QTest::addColumn<Qt3DRender::QShaderProgram::ShaderType>("type");
QTest::addColumn<QUrl>("graphUrl");
QTest::newRow("vertex") << Qt3DRender::QShaderProgram::Vertex
<< QUrl::fromEncoded("qrc:/vertex.json");
QTest::newRow("tessControl") << Qt3DRender::QShaderProgram::TessellationControl
<< QUrl::fromEncoded("qrc:/tesscontrol.json");
QTest::newRow("tessEval") << Qt3DRender::QShaderProgram::TessellationEvaluation
<< QUrl::fromEncoded("qrc:/tesseval.json");
QTest::newRow("geometry") << Qt3DRender::QShaderProgram::Geometry
<< QUrl::fromEncoded("qrc:/geometry.json");
QTest::newRow("fragment") << Qt3DRender::QShaderProgram::Fragment
<< QUrl::fromEncoded("qrc:/fragment.json");
QTest::newRow("compute") << Qt3DRender::QShaderProgram::Compute
<< QUrl::fromEncoded("qrc:/compute.json");
}
void shouldHandleShaderGraphPropertiesChanges()
{
// GIVEN
QFETCH(Qt3DRender::QShaderProgram::ShaderType, type);
QFETCH(QUrl, graphUrl);
Qt3DRender::Render::ShaderBuilder backend;
Qt3DRender::QShaderProgramBuilder frontend;
TestRenderer renderer;
backend.setRenderer(&renderer);
simulateInitializationSync(&frontend, &backend);
static const QHash<
Qt3DRender::QShaderProgram::ShaderType,
void (Qt3DRender::QShaderProgramBuilder::*)(const QUrl &)
>
shaderTypesToSetters = {
{Qt3DRender::QShaderProgram::Vertex, &Qt3DRender::QShaderProgramBuilder::setVertexShaderGraph},
{Qt3DRender::QShaderProgram::TessellationControl, &Qt3DRender::QShaderProgramBuilder::setTessellationControlShaderGraph},
{Qt3DRender::QShaderProgram::TessellationEvaluation, &Qt3DRender::QShaderProgramBuilder::setTessellationEvaluationShaderGraph},
{Qt3DRender::QShaderProgram::Geometry, &Qt3DRender::QShaderProgramBuilder::setGeometryShaderGraph},
{Qt3DRender::QShaderProgram::Fragment, &Qt3DRender::QShaderProgramBuilder::setFragmentShaderGraph},
{Qt3DRender::QShaderProgram::Compute, &Qt3DRender::QShaderProgramBuilder::setComputeShaderGraph},
};
// WHEN
(frontend.*(shaderTypesToSetters[type]))(QUrl());
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.shaderGraph(type), QUrl());
QVERIFY(!backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
QCOMPARE(renderer.dirtyBits(), 0);
renderer.resetDirty();
// WHEN
(frontend.*(shaderTypesToSetters[type]))(graphUrl);
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
(frontend.*(shaderTypesToSetters[type]))(QUrl());
backend.syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backend.shaderGraph(type), QUrl());
QVERIFY(backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
// WHEN
(frontend.*(shaderTypesToSetters[type]))(graphUrl);
backend.syncFromFrontEnd(&frontend, false);
// AND
backend.cleanup();
// THEN
QCOMPARE(backend.shaderGraph(type), QUrl());
QVERIFY(!backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
renderer.resetDirty();
}
void shouldHandleShaderCodeGeneration_data()
{
QTest::addColumn<Qt3DRender::QShaderProgram::ShaderType>("type");
QTest::newRow("vertex") << Qt3DRender::QShaderProgram::Vertex;
QTest::newRow("tessControl") << Qt3DRender::QShaderProgram::TessellationControl;
QTest::newRow("tessEval") << Qt3DRender::QShaderProgram::TessellationEvaluation;
QTest::newRow("geometry") << Qt3DRender::QShaderProgram::Geometry;
QTest::newRow("fragment") << Qt3DRender::QShaderProgram::Fragment;
QTest::newRow("compute") << Qt3DRender::QShaderProgram::Compute;
}
void shouldHandleShaderCodeGeneration()
{
// GIVEN
Qt3DRender::Render::ShaderBuilder::setPrototypesFile(":/prototypes.json");
QVERIFY(!Qt3DRender::Render::ShaderBuilder::getPrototypeNames().isEmpty());
QFETCH(Qt3DRender::QShaderProgram::ShaderType, type);
const auto gl3Api = []{
auto api = Qt3DRender::GraphicsApiFilterData();
api.m_api = Qt3DRender::QGraphicsApiFilter::OpenGL;
api.m_profile = Qt3DRender::QGraphicsApiFilter::CoreProfile;
api.m_major = 3;
api.m_minor = 2;
return api;
}();
const auto es2Api = []{
auto api = Qt3DRender::GraphicsApiFilterData();
api.m_api = Qt3DRender::QGraphicsApiFilter::OpenGLES;
api.m_major = 2;
api.m_minor = 0;
return api;
}();
const auto readCode = [](const QString &suffix) -> QString {
const auto filePath = QStringLiteral(":/output.") + suffix;
QFile file(filePath);
if (!file.open(QFile::ReadOnly | QFile::Text))
qFatal("File open failed: %s", qPrintable(filePath));
return file.readAll();
};
const auto gl3Code = readCode("gl3");
const auto es2Code = readCode("es2");
Qt3DRender::Render::ShaderBuilder backend;
// WHEN
const auto graphUrl = QUrl::fromEncoded("qrc:/input.json");
backend.setShaderGraph(type, graphUrl);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
// WHEN
backend.setGraphicsApi(gl3Api);
backend.generateCode(type);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(!backend.isShaderCodeDirty(type));
QCOMPARE(backend.shaderCode(type), gl3Code);
// WHEN
backend.setGraphicsApi(es2Api);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(backend.isShaderCodeDirty(type));
QCOMPARE(backend.shaderCode(type), gl3Code);
// WHEN
backend.generateCode(type);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(!backend.isShaderCodeDirty(type));
QCOMPARE(backend.shaderCode(type), es2Code);
}
void checkCodeUpdatedNotification_data()
{
QTest::addColumn<Qt3DRender::QShaderProgram::ShaderType>("type");
QTest::addColumn<Qt3DRender::QShaderProgram::ShaderType>("notificationType");
QTest::newRow("vertex") << Qt3DRender::QShaderProgram::Vertex << Qt3DRender::QShaderProgram::Vertex;
QTest::newRow("tessControl") << Qt3DRender::QShaderProgram::TessellationControl << Qt3DRender::QShaderProgram::TessellationControl;
QTest::newRow("tessEval") << Qt3DRender::QShaderProgram::TessellationEvaluation << Qt3DRender::QShaderProgram::TessellationEvaluation;
QTest::newRow("geometry") << Qt3DRender::QShaderProgram::Geometry << Qt3DRender::QShaderProgram::Geometry;
QTest::newRow("fragment") << Qt3DRender::QShaderProgram::Fragment << Qt3DRender::QShaderProgram::Fragment;
QTest::newRow("compute") << Qt3DRender::QShaderProgram::Compute << Qt3DRender::QShaderProgram::Compute;
}
void checkCodeUpdatedNotification()
{
// GIVEN
QSKIP("Disabled for Qt Base QShaderGenerator Integration");
Qt3DRender::Render::ShaderBuilder::setPrototypesFile(":/prototypes.json");
QVERIFY(!Qt3DRender::Render::ShaderBuilder::getPrototypeNames().isEmpty());
QFETCH(Qt3DRender::QShaderProgram::ShaderType, type);
QFETCH(Qt3DRender::QShaderProgram::ShaderType, notificationType);
const auto gl3Api = []{
auto api = Qt3DRender::GraphicsApiFilterData();
api.m_api = Qt3DRender::QGraphicsApiFilter::OpenGL;
api.m_profile = Qt3DRender::QGraphicsApiFilter::CoreProfile;
api.m_major = 3;
api.m_minor = 2;
return api;
}();
const auto readCode = [](const QString &suffix) -> QString {
const auto filePath = QStringLiteral(":/output.") + suffix;
QFile file(filePath);
if (!file.open(QFile::ReadOnly | QFile::Text))
qFatal("File open failed: %s", qPrintable(filePath));
return file.readAll();
};
const auto gl3Code = readCode("gl3");
Qt3DRender::Render::ShaderBuilder backend;
TestArbiter arbiter;
Qt3DCore::QBackendNodePrivate::get(&backend)->setArbiter(&arbiter);
// WHEN
const auto graphUrl = QUrl::fromEncoded("qrc:/input.json");
backend.setShaderGraph(type, graphUrl);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(backend.isShaderCodeDirty(type));
QVERIFY(backend.shaderCode(type).isEmpty());
// WHEN
backend.setGraphicsApi(gl3Api);
backend.generateCode(type);
// THEN
QCOMPARE(backend.shaderGraph(type), graphUrl);
QVERIFY(!backend.isShaderCodeDirty(type));
QCOMPARE(backend.shaderCode(type), gl3Code);
}
};
QTEST_MAIN(tst_ShaderBuilder)
#include "tst_shaderbuilder.moc"