qt5base-lts/tests/auto/gui/rhi/qshader/tst_qshader.cpp
Laszlo Agocs 53599592e0 Introduce the Qt graphics abstraction as private QtGui helpers
Comes with backends for Vulkan, Metal, Direct3D 11.1, and OpenGL (ES).

All APIs are private for now.

Shader conditioning (i.e. generating a QRhiShader in memory or on disk
from some shader source code) is done via the tools and APIs provided
by qt-labs/qtshadertools.

The OpenGL support follows the cross-platform tradition of requiring
ES 2.0 only, while optionally using some (ES) 3.x features. It can
operate in core profile contexts as well.

Task-number: QTBUG-70287
Change-Id: I246f2e36d562e404012c05db2aa72487108aa7cc
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
2019-06-13 10:13:45 +02:00

234 lines
8.6 KiB
C++

/****************************************************************************
**
** Copyright (C) 2019 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 <QtTest/QtTest>
#include <QFile>
#include <QtGui/private/qshaderdescription_p_p.h>
#include <QtGui/private/qshader_p_p.h>
class tst_QShader : public QObject
{
Q_OBJECT
private slots:
void simpleCompileCheckResults();
void genVariants();
void shaderDescImplicitSharing();
void bakedShaderImplicitSharing();
};
static QShader getShader(const QString &name)
{
QFile f(name);
if (f.open(QIODevice::ReadOnly))
return QShader::fromSerialized(f.readAll());
return QShader();
}
void tst_QShader::simpleCompileCheckResults()
{
QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
QVERIFY(s.isValid());
QCOMPARE(s.availableShaders().count(), 1);
const QShaderCode shader = s.shader(QShaderKey(QShader::SpirvShader,
QShaderVersion(100)));
QVERIFY(!shader.shader().isEmpty());
QCOMPARE(shader.entryPoint(), QByteArrayLiteral("main"));
const QShaderDescription desc = s.description();
QVERIFY(desc.isValid());
QCOMPARE(desc.inputVariables().count(), 2);
for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) {
switch (v.location) {
case 0:
QCOMPARE(v.name, QLatin1String("position"));
QCOMPARE(v.type, QShaderDescription::Vec4);
break;
case 1:
QCOMPARE(v.name, QLatin1String("color"));
QCOMPARE(v.type, QShaderDescription::Vec3);
break;
default:
QVERIFY(false);
break;
}
}
QCOMPARE(desc.outputVariables().count(), 1);
for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) {
switch (v.location) {
case 0:
QCOMPARE(v.name, QLatin1String("v_color"));
QCOMPARE(v.type, QShaderDescription::Vec3);
break;
default:
QVERIFY(false);
break;
}
}
QCOMPARE(desc.uniformBlocks().count(), 1);
const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first();
QCOMPARE(blk.blockName, QLatin1String("buf"));
QCOMPARE(blk.structName, QLatin1String("ubuf"));
QCOMPARE(blk.size, 68);
QCOMPARE(blk.binding, 0);
QCOMPARE(blk.descriptorSet, 0);
QCOMPARE(blk.members.count(), 2);
for (int i = 0; i < blk.members.count(); ++i) {
const QShaderDescription::BlockVariable v = blk.members[i];
switch (i) {
case 0:
QCOMPARE(v.offset, 0);
QCOMPARE(v.size, 64);
QCOMPARE(v.name, QLatin1String("mvp"));
QCOMPARE(v.type, QShaderDescription::Mat4);
QCOMPARE(v.matrixStride, 16);
break;
case 1:
QCOMPARE(v.offset, 64);
QCOMPARE(v.size, 4);
QCOMPARE(v.name, QLatin1String("opacity"));
QCOMPARE(v.type, QShaderDescription::Float);
break;
default:
QVERIFY(false);
break;
}
}
}
void tst_QShader::genVariants()
{
QShader s = getShader(QLatin1String(":/data/color.vert.qsb"));
// spirv, glsl 100, glsl 330, glsl 120, hlsl 50, msl 12
// + batchable variants
QVERIFY(s.isValid());
QCOMPARE(s.availableShaders().count(), 2 * 6);
int batchableVariantCount = 0;
int batchableGlslVariantCount = 0;
for (const QShaderKey &key : s.availableShaders()) {
if (key.sourceVariant() == QShader::BatchableVertexShader) {
++batchableVariantCount;
if (key.source() == QShader::GlslShader) {
++batchableGlslVariantCount;
const QByteArray src = s.shader(key).shader();
QVERIFY(src.contains(QByteArrayLiteral("_qt_order * ")));
}
}
}
QCOMPARE(batchableVariantCount, 6);
QCOMPARE(batchableGlslVariantCount, 3);
}
void tst_QShader::shaderDescImplicitSharing()
{
QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
QVERIFY(s.isValid());
QCOMPARE(s.availableShaders().count(), 1);
QVERIFY(s.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QShaderDescription d0 = s.description();
QVERIFY(d0.isValid());
QCOMPARE(d0.inputVariables().count(), 2);
QCOMPARE(d0.outputVariables().count(), 1);
QCOMPARE(d0.uniformBlocks().count(), 1);
QShaderDescription d1 = d0;
QVERIFY(QShaderDescriptionPrivate::get(&d0) == QShaderDescriptionPrivate::get(&d1));
QCOMPARE(d0.inputVariables().count(), 2);
QCOMPARE(d0.outputVariables().count(), 1);
QCOMPARE(d0.uniformBlocks().count(), 1);
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
d1.detach();
QVERIFY(QShaderDescriptionPrivate::get(&d0) != QShaderDescriptionPrivate::get(&d1));
QCOMPARE(d0.inputVariables().count(), 2);
QCOMPARE(d0.outputVariables().count(), 1);
QCOMPARE(d0.uniformBlocks().count(), 1);
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
}
void tst_QShader::bakedShaderImplicitSharing()
{
QShader s0 = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
QVERIFY(s0.isValid());
QCOMPARE(s0.availableShaders().count(), 1);
QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
{
QShader s1 = s0;
QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1));
QCOMPARE(s0.availableShaders().count(), 1);
QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QCOMPARE(s1.availableShaders().count(), 1);
QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QCOMPARE(s0.stage(), s1.stage());
QCOMPARE(s0, s1);
s1.detach();
QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1));
QCOMPARE(s0.availableShaders().count(), 1);
QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QCOMPARE(s1.availableShaders().count(), 1);
QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QCOMPARE(s0.stage(), s1.stage());
QCOMPARE(s0, s1);
}
{
QShader s1 = s0;
QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1));
QCOMPARE(s0.stage(), s1.stage());
s1.setStage(QShader::FragmentStage); // call a setter to trigger a detach
QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1));
QCOMPARE(s0.availableShaders().count(), 1);
QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QCOMPARE(s1.availableShaders().count(), 1);
QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
QShaderDescription d0 = s0.description();
QCOMPARE(d0.inputVariables().count(), 2);
QCOMPARE(d0.outputVariables().count(), 1);
QCOMPARE(d0.uniformBlocks().count(), 1);
QShaderDescription d1 = s1.description();
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
QVERIFY(s0 != s1);
}
}
#include <tst_qshader.moc>
QTEST_MAIN(tst_QShader)