diff options
Diffstat (limited to 'tests/auto/gui/rhi/qshader/tst_qshader.cpp')
-rw-r--r-- | tests/auto/gui/rhi/qshader/tst_qshader.cpp | 494 |
1 files changed, 331 insertions, 163 deletions
diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index 7cd87c80b6..9e179c95c3 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -1,35 +1,12 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QFile> -#include <QtGui/private/qshaderdescription_p_p.h> -#include <QtGui/private/qshader_p_p.h> +#include <QBuffer> + +#include <private/qshaderdescription_p.h> +#include <private/qshader_p.h> class tst_QShader : public QObject { @@ -41,11 +18,15 @@ private slots: void genVariants(); void shaderDescImplicitSharing(); void bakedShaderImplicitSharing(); + void sortedKeys(); void mslResourceMapping(); - void loadV3(); void serializeShaderDesc(); void comparison(); void loadV4(); + void manualShaderPackCreation(); + void loadV6WithSeparateImagesAndSamplers(); + void loadV7(); + void loadV8(); }; static QShader getShader(const QString &name) @@ -78,7 +59,7 @@ void tst_QShader::simpleCompileCheckResults() QShader s = getShader(QLatin1String(":/data/color_spirv_v5.vert.qsb")); QVERIFY(s.isValid()); QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 5); - QCOMPARE(s.availableShaders().count(), 1); + QCOMPARE(s.availableShaders().size(), 1); const QShaderCode shader = s.shader(QShaderKey(QShader::SpirvShader, QShaderVersion(100))); @@ -87,7 +68,7 @@ void tst_QShader::simpleCompileCheckResults() const QShaderDescription desc = s.description(); QVERIFY(desc.isValid()); - QCOMPARE(desc.inputVariables().count(), 2); + QCOMPARE(desc.inputVariables().size(), 2); for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) { switch (v.location) { case 0: @@ -99,11 +80,11 @@ void tst_QShader::simpleCompileCheckResults() QCOMPARE(v.type, QShaderDescription::Vec3); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Bad location: %1").arg(v.location))); break; } } - QCOMPARE(desc.outputVariables().count(), 1); + QCOMPARE(desc.outputVariables().size(), 1); for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) { switch (v.location) { case 0: @@ -111,19 +92,19 @@ void tst_QShader::simpleCompileCheckResults() QCOMPARE(v.type, QShaderDescription::Vec3); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Bad location: %1").arg(v.location))); break; } } - QCOMPARE(desc.uniformBlocks().count(), 1); + QCOMPARE(desc.uniformBlocks().size(), 1); const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first(); QCOMPARE(blk.blockName, QByteArrayLiteral("buf")); QCOMPARE(blk.structName, QByteArrayLiteral("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) { + QCOMPARE(blk.members.size(), 2); + for (int i = 0; i < blk.members.size(); ++i) { const QShaderDescription::BlockVariable v = blk.members[i]; switch (i) { case 0: @@ -140,7 +121,7 @@ void tst_QShader::simpleCompileCheckResults() QCOMPARE(v.type, QShaderDescription::Float); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Too many blocks: %1").arg(blk.members.size()))); break; } } @@ -153,7 +134,7 @@ void tst_QShader::genVariants() // + batchable variants QVERIFY(s.isValid()); QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 5); - QCOMPARE(s.availableShaders().count(), 2 * 6); + QCOMPARE(s.availableShaders().size(), 2 * 6); int batchableVariantCount = 0; int batchableGlslVariantCount = 0; @@ -176,33 +157,33 @@ void tst_QShader::shaderDescImplicitSharing() QShader s = getShader(QLatin1String(":/data/color_spirv_v5.vert.qsb")); QVERIFY(s.isValid()); QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 5); - QCOMPARE(s.availableShaders().count(), 1); + QCOMPARE(s.availableShaders().size(), 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); + QCOMPARE(d0.inputVariables().size(), 2); + QCOMPARE(d0.outputVariables().size(), 1); + QCOMPARE(d0.uniformBlocks().size(), 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); + QCOMPARE(d0.inputVariables().size(), 2); + QCOMPARE(d0.outputVariables().size(), 1); + QCOMPARE(d0.uniformBlocks().size(), 1); + QCOMPARE(d1.inputVariables().size(), 2); + QCOMPARE(d1.outputVariables().size(), 1); + QCOMPARE(d1.uniformBlocks().size(), 1); QCOMPARE(d0, d1); 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); + QCOMPARE(d0.inputVariables().size(), 2); + QCOMPARE(d0.outputVariables().size(), 1); + QCOMPARE(d0.uniformBlocks().size(), 1); + QCOMPARE(d1.inputVariables().size(), 2); + QCOMPARE(d1.outputVariables().size(), 1); + QCOMPARE(d1.uniformBlocks().size(), 1); QCOMPARE(d0, d1); d1 = QShaderDescription(); @@ -214,24 +195,24 @@ void tst_QShader::bakedShaderImplicitSharing() QShader s0 = getShader(QLatin1String(":/data/color_spirv_v5.vert.qsb")); QVERIFY(s0.isValid()); QCOMPARE(QShaderPrivate::get(&s0)->qsbVersion, 5); - QCOMPARE(s0.availableShaders().count(), 1); + QCOMPARE(s0.availableShaders().size(), 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); + QCOMPARE(s0.availableShaders().size(), 1); QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); - QCOMPARE(s1.availableShaders().count(), 1); + QCOMPARE(s1.availableShaders().size(), 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); + QCOMPARE(s0.availableShaders().size(), 1); QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); - QCOMPARE(s1.availableShaders().count(), 1); + QCOMPARE(s1.availableShaders().size(), 1); QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); QCOMPARE(s0.stage(), s1.stage()); QCOMPARE(s0, s1); @@ -244,22 +225,32 @@ void tst_QShader::bakedShaderImplicitSharing() s1.setStage(QShader::FragmentStage); // call a setter to trigger a detach QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1)); - QCOMPARE(s0.availableShaders().count(), 1); + QCOMPARE(s0.availableShaders().size(), 1); QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); - QCOMPARE(s1.availableShaders().count(), 1); + QCOMPARE(s1.availableShaders().size(), 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); + QCOMPARE(d0.inputVariables().size(), 2); + QCOMPARE(d0.outputVariables().size(), 1); + QCOMPARE(d0.uniformBlocks().size(), 1); QShaderDescription d1 = s1.description(); - QCOMPARE(d1.inputVariables().count(), 2); - QCOMPARE(d1.outputVariables().count(), 1); - QCOMPARE(d1.uniformBlocks().count(), 1); + QCOMPARE(d1.inputVariables().size(), 2); + QCOMPARE(d1.outputVariables().size(), 1); + QCOMPARE(d1.uniformBlocks().size(), 1); QVERIFY(s0 != s1); } } +void tst_QShader::sortedKeys() +{ + QShader s = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb")); + QVERIFY(s.isValid()); + QList<QShaderKey> availableShaders = s.availableShaders(); + QCOMPARE(availableShaders.size(), 7); + std::sort(availableShaders.begin(), availableShaders.end()); + QCOMPARE(availableShaders, s.availableShaders()); +} + void tst_QShader::mslResourceMapping() { QShader s = getShader(QLatin1String(":/data/texture_all_v4.frag.qsb")); @@ -267,7 +258,7 @@ void tst_QShader::mslResourceMapping() QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 4); const QList<QShaderKey> availableShaders = s.availableShaders(); - QCOMPARE(availableShaders.count(), 7); + QCOMPARE(availableShaders.size(), 7); QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50)))); @@ -276,93 +267,19 @@ void tst_QShader::mslResourceMapping() QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150)))); QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(330)))); - const QShader::NativeResourceBindingMap *resMap = + QShader::NativeResourceBindingMap resMap = s.nativeResourceBindingMap(QShaderKey(QShader::GlslShader, QShaderVersion(330))); - QVERIFY(!resMap); + QVERIFY(resMap.isEmpty()); // The Metal shader must come with a mapping table for binding points 0 // (uniform buffer) and 1 (combined image sampler mapped to a texture and // sampler in the shader). resMap = s.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))); - QVERIFY(resMap); + QVERIFY(!resMap.isEmpty()); - QCOMPARE(resMap->count(), 2); - QCOMPARE(resMap->value(0).first, 0); // mapped to native buffer index 0 - QCOMPARE(resMap->value(1), qMakePair(0, 0)); // mapped to native texture index 0 and sampler index 0 -} - -void tst_QShader::loadV3() -{ - // qsb version 3: QShaderDescription is serialized as CBOR. Ensure the deserialized data is as expected. - QShader s = getShader(QLatin1String(":/data/texture_all_v3.frag.qsb")); - QVERIFY(s.isValid()); - QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 3); - - const QList<QShaderKey> availableShaders = s.availableShaders(); - QCOMPARE(availableShaders.count(), 7); - QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(120)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150)))); - QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(330)))); - - const QShaderDescription desc = s.description(); - QVERIFY(desc.isValid()); - QCOMPARE(desc.inputVariables().count(), 1); - for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) { - switch (v.location) { - case 0: - QCOMPARE(v.name, QByteArrayLiteral("qt_TexCoord")); - QCOMPARE(v.type, QShaderDescription::Vec2); - 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, QByteArrayLiteral("fragColor")); - QCOMPARE(v.type, QShaderDescription::Vec4); - break; - default: - QVERIFY(false); - break; - } - } - QCOMPARE(desc.uniformBlocks().count(), 1); - const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first(); - QCOMPARE(blk.blockName, QByteArrayLiteral("buf")); - QCOMPARE(blk.structName, QByteArrayLiteral("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, QByteArrayLiteral("qt_Matrix")); - QCOMPARE(v.type, QShaderDescription::Mat4); - QCOMPARE(v.matrixStride, 16); - break; - case 1: - QCOMPARE(v.offset, 64); - QCOMPARE(v.size, 4); - QCOMPARE(v.name, QByteArrayLiteral("opacity")); - QCOMPARE(v.type, QShaderDescription::Float); - break; - default: - QVERIFY(false); - break; - } - } + QCOMPARE(resMap.size(), 2); + QCOMPARE(resMap.value(0).first, 0); // mapped to native buffer index 0 + QCOMPARE(resMap.value(1), qMakePair(0, 0)); // mapped to native texture index 0 and sampler index 0 } void tst_QShader::serializeShaderDesc() @@ -377,7 +294,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::WriteOnly)); - desc.serialize(&ds); + desc.serialize(&ds, QShaderPrivate::QSB_VERSION); } QVERIFY(!data.isEmpty()); @@ -402,7 +319,7 @@ void tst_QShader::serializeShaderDesc() QBuffer buf(&data); QDataStream ds(&buf); QVERIFY(buf.open(QIODevice::WriteOnly)); - desc.serialize(&ds); + desc.serialize(&ds, QShaderPrivate::QSB_VERSION); } QVERIFY(!data.isEmpty()); @@ -462,7 +379,7 @@ void tst_QShader::loadV4() QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 4); const QList<QShaderKey> availableShaders = s.availableShaders(); - QCOMPARE(availableShaders.count(), 7); + QCOMPARE(availableShaders.size(), 7); QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50)))); @@ -473,7 +390,7 @@ void tst_QShader::loadV4() const QShaderDescription desc = s.description(); QVERIFY(desc.isValid()); - QCOMPARE(desc.inputVariables().count(), 1); + QCOMPARE(desc.inputVariables().size(), 1); for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) { switch (v.location) { case 0: @@ -481,11 +398,11 @@ void tst_QShader::loadV4() QCOMPARE(v.type, QShaderDescription::Vec2); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Bad location: %1").arg(v.location))); break; } } - QCOMPARE(desc.outputVariables().count(), 1); + QCOMPARE(desc.outputVariables().size(), 1); for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) { switch (v.location) { case 0: @@ -493,19 +410,19 @@ void tst_QShader::loadV4() QCOMPARE(v.type, QShaderDescription::Vec4); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Bad location: %1").arg(v.location))); break; } } - QCOMPARE(desc.uniformBlocks().count(), 1); + QCOMPARE(desc.uniformBlocks().size(), 1); const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first(); QCOMPARE(blk.blockName, QByteArrayLiteral("buf")); QCOMPARE(blk.structName, QByteArrayLiteral("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) { + QCOMPARE(blk.members.size(), 2); + for (int i = 0; i < blk.members.size(); ++i) { const QShaderDescription::BlockVariable v = blk.members[i]; switch (i) { case 0: @@ -522,11 +439,262 @@ void tst_QShader::loadV4() QCOMPARE(v.type, QShaderDescription::Float); break; default: - QVERIFY(false); + QFAIL(qPrintable(QStringLiteral("Bad many blocks: %1").arg(blk.members.size()))); break; } } } +void tst_QShader::manualShaderPackCreation() +{ + // Exercise manually building a QShader (instead of loading it from + // serialized form). Some Qt modules may do this, in particular when OpenGL + // and GLSL code that cannot be processed through the normal pipeline with + // Vulkan SPIR-V as the primary target. + + static const char *FS = + "#extension GL_OES_EGL_image_external : require\n" + "varying vec2 v_texcoord;\n" + "struct buf {\n" + " mat4 qt_Matrix;\n" + " float qt_Opacity;\n" + "};\n" + "uniform buf ubuf;\n" + "uniform samplerExternalOES tex0;\n" + "void main()\n" + "{\n" + " gl_FragColor = ubuf.qt_Opacity * texture2D(tex0, v_texcoord);\n" + "}\n"; + static const char *FS_GLES_PREAMBLE = + "precision highp float;\n"; + // not necessarily sensible given the OES stuff but just for testing + static const char *FS_GL_PREAMBLE = + "#version 120\n"; + QByteArray fs_gles = FS_GLES_PREAMBLE; + fs_gles += FS; + QByteArray fs_gl = FS_GL_PREAMBLE; + fs_gl += FS; + + QShaderDescription desc; + QShaderDescriptionPrivate *descData = QShaderDescriptionPrivate::get(&desc); + QCOMPARE(descData->ref.loadRelaxed(), 1); + + // Inputs + QShaderDescription::InOutVariable texCoordInput; + texCoordInput.name = "v_texcoord"; + texCoordInput.type = QShaderDescription::Vec2; + texCoordInput.location = 0; + + descData->inVars = { + texCoordInput + }; + + // Outputs (just here for completeness, not strictly needed with OpenGL, the + // OpenGL backend of QRhi does not care) + QShaderDescription::InOutVariable fragColorOutput; + texCoordInput.name = "gl_FragColor"; + texCoordInput.type = QShaderDescription::Vec4; + texCoordInput.location = 0; + + descData->outVars = { + fragColorOutput + }; + + // No real uniform blocks in GLSL shaders used with QRhi, but metadata-wise + // that's what the struct maps to in others shading languages. + QShaderDescription::BlockVariable matrixBlockVar; + matrixBlockVar.name = "qt_Matrix"; + matrixBlockVar.type = QShaderDescription::Mat4; + matrixBlockVar.offset = 0; + matrixBlockVar.size = 64; + + QShaderDescription::BlockVariable opacityBlockVar; + opacityBlockVar.name = "qt_Opacity"; + opacityBlockVar.type = QShaderDescription::Float; + opacityBlockVar.offset = 64; + opacityBlockVar.size = 4; + + QShaderDescription::UniformBlock ubufStruct; + ubufStruct.blockName = "buf"; + ubufStruct.structName = "ubuf"; + ubufStruct.size = 64 + 4; + ubufStruct.binding = 0; + ubufStruct.members = { + matrixBlockVar, + opacityBlockVar + }; + + descData->uniformBlocks = { + ubufStruct + }; + + // Samplers + QShaderDescription::InOutVariable samplerTex0; + samplerTex0.name = "tex0"; + samplerTex0.type = QShaderDescription::SamplerExternalOES; + // the struct with the "uniform block" content should be binding 0, samplers can then use 1, 2, ... + samplerTex0.binding = 1; + + descData->combinedImageSamplers = { + samplerTex0 + }; + + // Now we have everything needed to construct a QShader suitable for OpenGL ES >=2.0 and OpenGL >=2.1 + QShader shaderPack; + shaderPack.setStage(QShader::FragmentStage); + shaderPack.setDescription(desc); + shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)), QShaderCode(fs_gles)); + shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(120)), QShaderCode(fs_gl)); + + // real world code would then pass the QShader to QSGMaterialShader::setShader() etc. + + const QByteArray serialized = shaderPack.serialized(); + QShader newShaderPack = QShader::fromSerialized(serialized); + QCOMPARE(newShaderPack.availableShaders().size(), 2); + QCOMPARE(newShaderPack.description().inputVariables().size(), 1); + QCOMPARE(newShaderPack.description().outputVariables().size(), 1); + QCOMPARE(newShaderPack.description().uniformBlocks().size(), 1); + QCOMPARE(newShaderPack.description().combinedImageSamplers().size(), 1); + QCOMPARE(newShaderPack.shader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs))).shader(), fs_gles); + QCOMPARE(newShaderPack.shader(QShaderKey(QShader::GlslShader, QShaderVersion(120))).shader(), fs_gl); +} + +void tst_QShader::loadV6WithSeparateImagesAndSamplers() +{ + QShader s = getShader(QLatin1String(":/data/texture_sep_v6.frag.qsb")); + QVERIFY(s.isValid()); + QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 6); + + const QList<QShaderKey> availableShaders = s.availableShaders(); + QCOMPARE(availableShaders.size(), 6); + QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(120)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150)))); + + QShader::NativeResourceBindingMap resMap = + s.nativeResourceBindingMap(QShaderKey(QShader::HlslShader, QShaderVersion(50))); + QVERIFY(resMap.size() == 4); + QVERIFY(s.separateToCombinedImageSamplerMappingList(QShaderKey(QShader::HlslShader, QShaderVersion(50))).isEmpty()); + resMap = s.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))); + QVERIFY(resMap.size() == 4); + QVERIFY(s.separateToCombinedImageSamplerMappingList(QShaderKey(QShader::MslShader, QShaderVersion(12))).isEmpty()); + + for (auto key : { + QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)), + QShaderKey(QShader::GlslShader, QShaderVersion(120)), + QShaderKey(QShader::GlslShader, QShaderVersion(150)) }) + { + auto list = s.separateToCombinedImageSamplerMappingList(key); + QCOMPARE(list.size(), 2); + } +} + +void tst_QShader::loadV7() +{ + QShader vert = getShader(QLatin1String(":/data/metal_enabled_tessellation_v7.vert.qsb")); + QVERIFY(vert.isValid()); + QCOMPARE(QShaderPrivate::get(&vert)->qsbVersion, 7); + QCOMPARE(vert.availableShaders().size(), 8); + + QCOMPARE(vert.description().inputVariables().size(), 2); + QCOMPARE(vert.description().outputBuiltinVariables().size(), 1); + QCOMPARE(vert.description().outputBuiltinVariables()[0].type, QShaderDescription::PositionBuiltin); + QCOMPARE(vert.description().outputVariables().size(), 1); + QCOMPARE(vert.description().outputVariables()[0].name, QByteArrayLiteral("v_color")); + + QVERIFY(vert.availableShaders().contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); + QVERIFY(!vert.shader(QShaderKey(QShader::MslShader, QShaderVersion(12), QShader::NonIndexedVertexAsComputeShader)).shader().isEmpty()); + QVERIFY(!vert.shader(QShaderKey(QShader::MslShader, QShaderVersion(12), QShader::UInt16IndexedVertexAsComputeShader)).shader().isEmpty()); + QVERIFY(!vert.shader(QShaderKey(QShader::MslShader, QShaderVersion(12), QShader::UInt32IndexedVertexAsComputeShader)).shader().isEmpty()); + + QShader tesc = getShader(QLatin1String(":/data/metal_enabled_tessellation_v7.tesc.qsb")); + QVERIFY(tesc.isValid()); + QCOMPARE(QShaderPrivate::get(&tesc)->qsbVersion, 7); + QCOMPARE(tesc.availableShaders().size(), 5); + QCOMPARE(tesc.description().tessellationOutputVertexCount(), 3u); + + QCOMPARE(tesc.description().inputBuiltinVariables().size(), 2); + QCOMPARE(tesc.description().outputBuiltinVariables().size(), 3); + // builtins must be sorted based on the type + QCOMPARE(tesc.description().inputBuiltinVariables()[0].type, QShaderDescription::PositionBuiltin); + QCOMPARE(tesc.description().inputBuiltinVariables()[1].type, QShaderDescription::InvocationIdBuiltin); + QCOMPARE(tesc.description().outputBuiltinVariables()[0].type, QShaderDescription::PositionBuiltin); + QCOMPARE(tesc.description().outputBuiltinVariables()[1].type, QShaderDescription::TessLevelOuterBuiltin); + QCOMPARE(tesc.description().outputBuiltinVariables()[2].type, QShaderDescription::TessLevelInnerBuiltin); + + QCOMPARE(tesc.description().outputVariables().size(), 3); + for (const QShaderDescription::InOutVariable &v : tesc.description().outputVariables()) { + switch (v.location) { + case 0: + QCOMPARE(v.name, QByteArrayLiteral("outColor")); + QCOMPARE(v.type, QShaderDescription::Vec3); + QCOMPARE(v.perPatch, false); + break; + case 1: + QCOMPARE(v.name, QByteArrayLiteral("stuff")); + QCOMPARE(v.type, QShaderDescription::Vec3); + QCOMPARE(v.perPatch, true); + break; + case 2: + QCOMPARE(v.name, QByteArrayLiteral("more_stuff")); + QCOMPARE(v.type, QShaderDescription::Float); + QCOMPARE(v.perPatch, true); + break; + default: + QFAIL(qPrintable(QStringLiteral("Bad location: %1").arg(v.location))); + break; + } + } + + QVERIFY(!tesc.shader(QShaderKey(QShader::MslShader, QShaderVersion(12))).shader().isEmpty()); + QCOMPARE(tesc.nativeShaderInfo(QShaderKey(QShader::SpirvShader, QShaderVersion(100))).extraBufferBindings.size(), 0); + QCOMPARE(tesc.nativeShaderInfo(QShaderKey(QShader::MslShader, QShaderVersion(12))).extraBufferBindings.size(), 5); + + QShader tese = getShader(QLatin1String(":/data/metal_enabled_tessellation_v7.tese.qsb")); + QVERIFY(tese.isValid()); + QCOMPARE(QShaderPrivate::get(&tese)->qsbVersion, 7); + QCOMPARE(tese.availableShaders().size(), 5); + QCOMPARE(tese.description().tessellationMode(), QShaderDescription::TrianglesTessellationMode); + QCOMPARE(tese.description().tessellationWindingOrder(), QShaderDescription::CcwTessellationWindingOrder); + QCOMPARE(tese.description().tessellationPartitioning(), QShaderDescription::FractionalOddTessellationPartitioning); + + QCOMPARE(tese.description().inputBuiltinVariables()[0].type, QShaderDescription::PositionBuiltin); + QCOMPARE(tese.description().inputBuiltinVariables()[1].type, QShaderDescription::TessLevelOuterBuiltin); + QCOMPARE(tese.description().inputBuiltinVariables()[2].type, QShaderDescription::TessLevelInnerBuiltin); + QCOMPARE(tese.description().inputBuiltinVariables()[3].type, QShaderDescription::TessCoordBuiltin); + + QCOMPARE(tese.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))).size(), 1); + QCOMPARE(tese.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12))).value(0), qMakePair(0, -1)); + + QShader frag = getShader(QLatin1String(":/data/metal_enabled_tessellation_v7.frag.qsb")); + QVERIFY(frag.isValid()); + QCOMPARE(QShaderPrivate::get(&frag)->qsbVersion, 7); +} + +void tst_QShader::loadV8() +{ + QShader s = getShader(QLatin1String(":/data/storage_buffer_info_v8.comp.qsb")); + QVERIFY(s.isValid()); + QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 8); + + const QList<QShaderKey> availableShaders = s.availableShaders(); + QCOMPARE(availableShaders.size(), 5); + QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50)))); + QVERIFY(availableShaders.contains( + QShaderKey(QShader::GlslShader, QShaderVersion(310, QShaderVersion::GlslEs)))); + QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(430)))); + + QCOMPARE(s.description().storageBlocks().size(), 1); + QCOMPARE(s.description().storageBlocks().last().runtimeArrayStride, 4); + QCOMPARE(s.description().storageBlocks().last().qualifierFlags, + QShaderDescription::QualifierFlags(QShaderDescription::QualifierWriteOnly + | QShaderDescription::QualifierRestrict)); +} + #include <tst_qshader.moc> QTEST_MAIN(tst_QShader) |