1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30#include <QFile>
31#include <QtGui/private/qshaderdescription_p_p.h>
32#include <QtGui/private/qshader_p_p.h>
33
34class tst_QShader : public QObject
35{
36 Q_OBJECT
37
38private slots:
39 void simpleCompileCheckResults();
40 void genVariants();
41 void shaderDescImplicitSharing();
42 void bakedShaderImplicitSharing();
43};
44
45static QShader getShader(const QString &name)
46{
47 QFile f(name);
48 if (f.open(QIODevice::ReadOnly))
49 return QShader::fromSerialized(f.readAll());
50
51 return QShader();
52}
53
54void tst_QShader::simpleCompileCheckResults()
55{
56 QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
57 QVERIFY(s.isValid());
58 QCOMPARE(s.availableShaders().count(), 1);
59
60 const QShaderCode shader = s.shader(QShaderKey(QShader::SpirvShader,
61 QShaderVersion(100)));
62 QVERIFY(!shader.shader().isEmpty());
63 QCOMPARE(shader.entryPoint(), QByteArrayLiteral("main"));
64
65 const QShaderDescription desc = s.description();
66 QVERIFY(desc.isValid());
67 QCOMPARE(desc.inputVariables().count(), 2);
68 for (const QShaderDescription::InOutVariable &v : desc.inputVariables()) {
69 switch (v.location) {
70 case 0:
71 QCOMPARE(v.name, QLatin1String("position"));
72 QCOMPARE(v.type, QShaderDescription::Vec4);
73 break;
74 case 1:
75 QCOMPARE(v.name, QLatin1String("color"));
76 QCOMPARE(v.type, QShaderDescription::Vec3);
77 break;
78 default:
79 QVERIFY(false);
80 break;
81 }
82 }
83 QCOMPARE(desc.outputVariables().count(), 1);
84 for (const QShaderDescription::InOutVariable &v : desc.outputVariables()) {
85 switch (v.location) {
86 case 0:
87 QCOMPARE(v.name, QLatin1String("v_color"));
88 QCOMPARE(v.type, QShaderDescription::Vec3);
89 break;
90 default:
91 QVERIFY(false);
92 break;
93 }
94 }
95 QCOMPARE(desc.uniformBlocks().count(), 1);
96 const QShaderDescription::UniformBlock blk = desc.uniformBlocks().first();
97 QCOMPARE(blk.blockName, QLatin1String("buf"));
98 QCOMPARE(blk.structName, QLatin1String("ubuf"));
99 QCOMPARE(blk.size, 68);
100 QCOMPARE(blk.binding, 0);
101 QCOMPARE(blk.descriptorSet, 0);
102 QCOMPARE(blk.members.count(), 2);
103 for (int i = 0; i < blk.members.count(); ++i) {
104 const QShaderDescription::BlockVariable v = blk.members[i];
105 switch (i) {
106 case 0:
107 QCOMPARE(v.offset, 0);
108 QCOMPARE(v.size, 64);
109 QCOMPARE(v.name, QLatin1String("mvp"));
110 QCOMPARE(v.type, QShaderDescription::Mat4);
111 QCOMPARE(v.matrixStride, 16);
112 break;
113 case 1:
114 QCOMPARE(v.offset, 64);
115 QCOMPARE(v.size, 4);
116 QCOMPARE(v.name, QLatin1String("opacity"));
117 QCOMPARE(v.type, QShaderDescription::Float);
118 break;
119 default:
120 QVERIFY(false);
121 break;
122 }
123 }
124}
125
126void tst_QShader::genVariants()
127{
128 QShader s = getShader(QLatin1String(":/data/color.vert.qsb"));
129 // spirv, glsl 100, glsl 330, glsl 120, hlsl 50, msl 12
130 // + batchable variants
131 QVERIFY(s.isValid());
132 QCOMPARE(s.availableShaders().count(), 2 * 6);
133
134 int batchableVariantCount = 0;
135 int batchableGlslVariantCount = 0;
136 for (const QShaderKey &key : s.availableShaders()) {
137 if (key.sourceVariant() == QShader::BatchableVertexShader) {
138 ++batchableVariantCount;
139 if (key.source() == QShader::GlslShader) {
140 ++batchableGlslVariantCount;
141 const QByteArray src = s.shader(key).shader();
142 QVERIFY(src.contains(QByteArrayLiteral("_qt_order * ")));
143 }
144 }
145 }
146 QCOMPARE(batchableVariantCount, 6);
147 QCOMPARE(batchableGlslVariantCount, 3);
148}
149
150void tst_QShader::shaderDescImplicitSharing()
151{
152 QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
153 QVERIFY(s.isValid());
154 QCOMPARE(s.availableShaders().count(), 1);
155 QVERIFY(s.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
156
157 QShaderDescription d0 = s.description();
158 QVERIFY(d0.isValid());
159 QCOMPARE(d0.inputVariables().count(), 2);
160 QCOMPARE(d0.outputVariables().count(), 1);
161 QCOMPARE(d0.uniformBlocks().count(), 1);
162
163 QShaderDescription d1 = d0;
164 QVERIFY(QShaderDescriptionPrivate::get(&d0) == QShaderDescriptionPrivate::get(&d1));
165 QCOMPARE(d0.inputVariables().count(), 2);
166 QCOMPARE(d0.outputVariables().count(), 1);
167 QCOMPARE(d0.uniformBlocks().count(), 1);
168 QCOMPARE(d1.inputVariables().count(), 2);
169 QCOMPARE(d1.outputVariables().count(), 1);
170 QCOMPARE(d1.uniformBlocks().count(), 1);
171
172 d1.detach();
173 QVERIFY(QShaderDescriptionPrivate::get(&d0) != QShaderDescriptionPrivate::get(&d1));
174 QCOMPARE(d0.inputVariables().count(), 2);
175 QCOMPARE(d0.outputVariables().count(), 1);
176 QCOMPARE(d0.uniformBlocks().count(), 1);
177 QCOMPARE(d1.inputVariables().count(), 2);
178 QCOMPARE(d1.outputVariables().count(), 1);
179 QCOMPARE(d1.uniformBlocks().count(), 1);
180}
181
182void tst_QShader::bakedShaderImplicitSharing()
183{
184 QShader s0 = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
185 QVERIFY(s0.isValid());
186 QCOMPARE(s0.availableShaders().count(), 1);
187 QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
188
189 {
190 QShader s1 = s0;
191 QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1));
192 QCOMPARE(s0.availableShaders().count(), 1);
193 QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
194 QCOMPARE(s1.availableShaders().count(), 1);
195 QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
196 QCOMPARE(s0.stage(), s1.stage());
197 QCOMPARE(s0, s1);
198
199 s1.detach();
200 QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1));
201 QCOMPARE(s0.availableShaders().count(), 1);
202 QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
203 QCOMPARE(s1.availableShaders().count(), 1);
204 QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
205 QCOMPARE(s0.stage(), s1.stage());
206 QCOMPARE(s0, s1);
207 }
208
209 {
210 QShader s1 = s0;
211 QVERIFY(QShaderPrivate::get(&s0) == QShaderPrivate::get(&s1));
212 QCOMPARE(s0.stage(), s1.stage());
213
214 s1.setStage(QShader::FragmentStage); // call a setter to trigger a detach
215 QVERIFY(QShaderPrivate::get(&s0) != QShaderPrivate::get(&s1));
216 QCOMPARE(s0.availableShaders().count(), 1);
217 QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
218 QCOMPARE(s1.availableShaders().count(), 1);
219 QVERIFY(s1.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
220 QShaderDescription d0 = s0.description();
221 QCOMPARE(d0.inputVariables().count(), 2);
222 QCOMPARE(d0.outputVariables().count(), 1);
223 QCOMPARE(d0.uniformBlocks().count(), 1);
224 QShaderDescription d1 = s1.description();
225 QCOMPARE(d1.inputVariables().count(), 2);
226 QCOMPARE(d1.outputVariables().count(), 1);
227 QCOMPARE(d1.uniformBlocks().count(), 1);
228 QVERIFY(s0 != s1);
229 }
230}
231
232#include <tst_qshader.moc>
233QTEST_MAIN(tst_QShader)
234