summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-10-28 16:37:57 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-10-29 15:22:46 +0100
commit58a67e4e0a88e52d71eef5d08df1465f7ac610ae (patch)
tree3d2a0ab28a8ee031f54165302f52df2de8a08fd8
parentc87e2c37de439996895fc2e2e4c79376b6ec1f09 (diff)
rhi: Move to CBOR in QShader and expand the autotest
Binary JSON is said to become deprecated. Therefore, add support for CBOR. Binary JSON is still supported for deserialization, so all existing .qsb files will continue to work, as long as the binaryjson feature is enabled in the Qt build. Also makes QShaderDescription comparable. This is important for tests in particular. A nice side effect of using CBOR is that .qsb files become smaller. For a typical Qt Quick material shader this can mean a reduction of 300 bytes or more. Task-number: QTBUG-79576 Change-Id: I5547c0266e3e8128c9653e954e47487352267f71 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
-rw-r--r--src/gui/rhi/qshader.cpp23
-rw-r--r--src/gui/rhi/qshader_p_p.h6
-rw-r--r--src/gui/rhi/qshaderdescription.cpp152
-rw-r--r--src/gui/rhi/qshaderdescription_p.h40
-rw-r--r--tests/auto/gui/rhi/qshader/data/README15
-rw-r--r--tests/auto/gui/rhi/qshader/data/color_all_v1.vert.qsb (renamed from tests/auto/gui/rhi/qshader/data/color.vert.qsb)bin1847 -> 1847 bytes
-rw-r--r--tests/auto/gui/rhi/qshader/data/color_spirv_v1.vert.qsb (renamed from tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb)bin813 -> 813 bytes
-rw-r--r--tests/auto/gui/rhi/qshader/data/texture.frag16
-rw-r--r--tests/auto/gui/rhi/qshader/data/texture_all_v2.frag.qsbbin0 -> 1691 bytes
-rw-r--r--tests/auto/gui/rhi/qshader/data/texture_all_v3.frag.qsbbin0 -> 1432 bytes
-rw-r--r--tests/auto/gui/rhi/qshader/tst_qshader.cpp174
11 files changed, 410 insertions, 16 deletions
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index c22b029dc8..14d780b4e4 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -214,9 +214,6 @@ QT_BEGIN_NAMESPACE
QShader, it indicates no shader code was found for the requested key.
*/
-static const int QSB_VERSION = 2;
-static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
-
/*!
Constructs a new, empty (and thus invalid) QShader instance.
*/
@@ -368,9 +365,9 @@ QByteArray QShader::serialized() const
if (!buf.open(QIODevice::WriteOnly))
return QByteArray();
- ds << QSB_VERSION;
+ ds << QShaderPrivate::QSB_VERSION;
ds << d->stage;
- ds << d->desc.toBinaryJson();
+ ds << d->desc.toCbor();
ds << d->shaders.count();
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
@@ -429,9 +426,12 @@ QShader QShader::fromSerialized(const QByteArray &data)
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
int intVal;
ds >> intVal;
- const int qsbVersion = intVal;
- if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
- qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion);
+ d->qsbVersion = intVal;
+ if (d->qsbVersion != QShaderPrivate::QSB_VERSION
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS)
+ {
+ qWarning("Attempted to deserialize QShader with unknown version %d.", d->qsbVersion);
return QShader();
}
@@ -439,7 +439,10 @@ QShader QShader::fromSerialized(const QByteArray &data)
d->stage = Stage(intVal);
QByteArray descBin;
ds >> descBin;
- d->desc = QShaderDescription::fromBinaryJson(descBin);
+ if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON)
+ d->desc = QShaderDescription::fromCbor(descBin);
+ else
+ d->desc = QShaderDescription::fromBinaryJson(descBin);
int count;
ds >> count;
for (int i = 0; i < count; ++i) {
@@ -454,7 +457,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
d->shaders[k] = shader;
}
- if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
+ if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) {
ds >> count;
for (int i = 0; i < count; ++i) {
QShaderKey k;
diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h
index 4535e01491..8c89f2b45f 100644
--- a/src/gui/rhi/qshader_p_p.h
+++ b/src/gui/rhi/qshader_p_p.h
@@ -57,6 +57,10 @@ QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QShaderPrivate
{
+ static const int QSB_VERSION = 3;
+ static const int QSB_VERSION_WITH_BINARY_JSON = 2;
+ static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
+
QShaderPrivate()
: ref(1)
{
@@ -64,6 +68,7 @@ struct Q_GUI_EXPORT QShaderPrivate
QShaderPrivate(const QShaderPrivate *other)
: ref(1),
+ qsbVersion(other->qsbVersion),
stage(other->stage),
desc(other->desc),
shaders(other->shaders),
@@ -75,6 +80,7 @@ struct Q_GUI_EXPORT QShaderPrivate
static const QShaderPrivate *get(const QShader *s) { return s->d; }
QAtomicInt ref;
+ int qsbVersion = QSB_VERSION;
QShader::Stage stage = QShader::VertexStage;
QShaderDescription desc;
QHash<QShaderKey, QShaderCode> shaders;
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp
index 179d5f3a07..d0f73f6aa7 100644
--- a/src/gui/rhi/qshaderdescription.cpp
+++ b/src/gui/rhi/qshaderdescription.cpp
@@ -38,6 +38,9 @@
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
+#include <QCborValue>
+#include <QCborMap>
+#include <QCborArray>
QT_BEGIN_NAMESPACE
@@ -335,11 +338,27 @@ bool QShaderDescription::isValid() const
/*!
\return a serialized binary version of the data.
- \sa toJson()
+ \sa toJson(), toCbor()
*/
QByteArray QShaderDescription::toBinaryJson() const
{
+#if QT_CONFIG(binaryjson)
return d->makeDoc().toBinaryData();
+#else
+ qWarning("Cannot generate binary JSON from QShaderDescription due to disabled binaryjson feature");
+ return QByteArray();
+#endif
+}
+
+/*!
+ \return a serialized binary version of the data in CBOR (Concise Binary
+ Object Representation) format.
+
+ \sa QCborValue, toBinaryJson(), toJson()
+ */
+QByteArray QShaderDescription::toCbor() const
+{
+ return QCborValue::fromJsonValue(d->makeDoc().object()).toCbor();
}
/*!
@@ -347,7 +366,7 @@ QByteArray QShaderDescription::toBinaryJson() const
\note There is no deserialization method provided for JSON text.
- \sa toBinaryJson()
+ \sa toBinaryJson(), toCbor()
*/
QByteArray QShaderDescription::toJson() const
{
@@ -357,11 +376,38 @@ QByteArray QShaderDescription::toJson() const
/*!
Deserializes the given binary JSON \a data and returns a new
QShaderDescription.
+
+ \sa fromCbor()
*/
QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data)
{
QShaderDescription desc;
+#if QT_CONFIG(binaryjson)
QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data));
+#else
+ Q_UNUSED(data);
+ qWarning("Cannot load QShaderDescription from binary JSON due to disabled binaryjson feature");
+#endif
+ return desc;
+}
+
+/*!
+ Deserializes the given CBOR \a data and returns a new QShaderDescription.
+
+ \sa fromBinaryJson()
+ */
+QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
+{
+ QShaderDescription desc;
+ const QCborValue cbor = QCborValue::fromCbor(data);
+ if (cbor.isMap()) {
+ const QJsonDocument doc(cbor.toMap().toJsonObject());
+ QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
+ }
+ if (cbor.isArray()) {
+ const QJsonDocument doc(cbor.toArray().toJsonArray());
+ QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
+ }
return desc;
}
@@ -1119,4 +1165,106 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
}
}
+/*!
+ Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription
+ */
+bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW
+{
+ if (lhs.d == rhs.d)
+ return true;
+
+ return lhs.d->inVars == rhs.d->inVars
+ && lhs.d->outVars == rhs.d->outVars
+ && lhs.d->uniformBlocks == rhs.d->uniformBlocks
+ && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks
+ && lhs.d->storageBlocks == rhs.d->storageBlocks
+ && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers
+ && lhs.d->storageImages == rhs.d->storageImages
+ && lhs.d->localSize == rhs.d->localSize;
+}
+
+/*!
+ Returns \c true if the two InOutVariable objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::InOutVariable
+ */
+bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.type == rhs.type
+ && lhs.location == rhs.location
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.imageFormat == rhs.imageFormat
+ && lhs.imageFlags == rhs.imageFlags;
+}
+
+/*!
+ Returns \c true if the two BlockVariable objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::BlockVariable
+ */
+bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.type == rhs.type
+ && lhs.offset == rhs.offset
+ && lhs.size == rhs.size
+ && lhs.arrayDims == rhs.arrayDims
+ && lhs.arrayStride == rhs.arrayStride
+ && lhs.matrixStride == rhs.matrixStride
+ && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor
+ && lhs.structMembers == rhs.structMembers;
+}
+
+/*!
+ Returns \c true if the two UniformBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::UniformBlock
+ */
+bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.blockName == rhs.blockName
+ && lhs.structName == rhs.structName
+ && lhs.size == rhs.size
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.members == rhs.members;
+}
+
+/*!
+ Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::PushConstantBlock
+ */
+bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.size == rhs.size
+ && lhs.members == rhs.members;
+}
+
+/*!
+ Returns \c true if the two StorageBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::StorageBlock
+ */
+bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.blockName == rhs.blockName
+ && lhs.instanceName == rhs.instanceName
+ && lhs.knownSize == rhs.knownSize
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.members == rhs.members;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h
index 5a63b998cd..e02a53dcb5 100644
--- a/src/gui/rhi/qshaderdescription_p.h
+++ b/src/gui/rhi/qshaderdescription_p.h
@@ -69,9 +69,11 @@ public:
bool isValid() const;
QByteArray toBinaryJson() const;
+ QByteArray toCbor() const;
QByteArray toJson() const;
static QShaderDescription fromBinaryJson(const QByteArray &data);
+ static QShaderDescription fromCbor(const QByteArray &data);
enum VariableType {
Unknown = 0,
@@ -263,6 +265,7 @@ private:
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
#endif
+ friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
@@ -276,6 +279,43 @@ Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlo
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
#endif
+Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
QT_END_NAMESPACE
#endif
diff --git a/tests/auto/gui/rhi/qshader/data/README b/tests/auto/gui/rhi/qshader/data/README
new file mode 100644
index 0000000000..3d89f2a0c5
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/README
@@ -0,0 +1,15 @@
+Warning: Do NOT regenerate the .qsb files without proper planning and understanding
+the following.
+
+Among other things, we are also testing backwards compatibility for QShader
+deserialization.
+
+.qsb files with _v1 in the name were produced with an older qtshadertools
+and have a QSB_VERSION of 1.
+
+Files with _v2 are generated with a newer qsb, those have QSB_VERSION 2.
+The difference is the support for nativeResourceBindingMap() which is only
+present in v2.
+
+Files with _v3 come from an even newer qsb, and have QSB_VERSION 3. The
+difference to 2 is the use of CBOR instead of binary JSON for QShaderDescription.
diff --git a/tests/auto/gui/rhi/qshader/data/color.vert.qsb b/tests/auto/gui/rhi/qshader/data/color_all_v1.vert.qsb
index 7d02d823d2..7d02d823d2 100644
--- a/tests/auto/gui/rhi/qshader/data/color.vert.qsb
+++ b/tests/auto/gui/rhi/qshader/data/color_all_v1.vert.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb b/tests/auto/gui/rhi/qshader/data/color_spirv_v1.vert.qsb
index c82ba7e8e7..c82ba7e8e7 100644
--- a/tests/auto/gui/rhi/qshader/data/color_simple.vert.qsb
+++ b/tests/auto/gui/rhi/qshader/data/color_spirv_v1.vert.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qshader/data/texture.frag b/tests/auto/gui/rhi/qshader/data/texture.frag
new file mode 100644
index 0000000000..bd22f817e0
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/texture.frag
@@ -0,0 +1,16 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float opacity;
+} ubuf;
+
+layout(binding = 1) uniform sampler2D qt_Texture;
+
+void main()
+{
+ fragColor = texture(qt_Texture, qt_TexCoord) * ubuf.opacity;
+}
diff --git a/tests/auto/gui/rhi/qshader/data/texture_all_v2.frag.qsb b/tests/auto/gui/rhi/qshader/data/texture_all_v2.frag.qsb
new file mode 100644
index 0000000000..79f5486945
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/texture_all_v2.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qshader/data/texture_all_v3.frag.qsb b/tests/auto/gui/rhi/qshader/data/texture_all_v3.frag.qsb
new file mode 100644
index 0000000000..b6e49aa03d
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/texture_all_v3.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp
index 21f0cc7895..a0082f1e3b 100644
--- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp
+++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp
@@ -40,6 +40,9 @@ private slots:
void genVariants();
void shaderDescImplicitSharing();
void bakedShaderImplicitSharing();
+ void mslResourceMapping();
+ void loadV3();
+ void serializeShaderDesc();
};
static QShader getShader(const QString &name)
@@ -53,8 +56,9 @@ static QShader getShader(const QString &name)
void tst_QShader::simpleCompileCheckResults()
{
- QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
+ QShader s = getShader(QLatin1String(":/data/color_spirv_v1.vert.qsb"));
QVERIFY(s.isValid());
+ QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 1);
QCOMPARE(s.availableShaders().count(), 1);
const QShaderCode shader = s.shader(QShaderKey(QShader::SpirvShader,
@@ -125,10 +129,11 @@ void tst_QShader::simpleCompileCheckResults()
void tst_QShader::genVariants()
{
- QShader s = getShader(QLatin1String(":/data/color.vert.qsb"));
+ QShader s = getShader(QLatin1String(":/data/color_all_v1.vert.qsb"));
// spirv, glsl 100, glsl 330, glsl 120, hlsl 50, msl 12
// + batchable variants
QVERIFY(s.isValid());
+ QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 1);
QCOMPARE(s.availableShaders().count(), 2 * 6);
int batchableVariantCount = 0;
@@ -149,8 +154,9 @@ void tst_QShader::genVariants()
void tst_QShader::shaderDescImplicitSharing()
{
- QShader s = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
+ QShader s = getShader(QLatin1String(":/data/color_spirv_v1.vert.qsb"));
QVERIFY(s.isValid());
+ QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 1);
QCOMPARE(s.availableShaders().count(), 1);
QVERIFY(s.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
@@ -168,6 +174,7 @@ void tst_QShader::shaderDescImplicitSharing()
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
+ QCOMPARE(d0, d1);
d1.detach();
QVERIFY(QShaderDescriptionPrivate::get(&d0) != QShaderDescriptionPrivate::get(&d1));
@@ -177,12 +184,17 @@ void tst_QShader::shaderDescImplicitSharing()
QCOMPARE(d1.inputVariables().count(), 2);
QCOMPARE(d1.outputVariables().count(), 1);
QCOMPARE(d1.uniformBlocks().count(), 1);
+ QCOMPARE(d0, d1);
+
+ d1 = QShaderDescription();
+ QVERIFY(d0 != d1);
}
void tst_QShader::bakedShaderImplicitSharing()
{
- QShader s0 = getShader(QLatin1String(":/data/color_simple.vert.qsb"));
+ QShader s0 = getShader(QLatin1String(":/data/color_spirv_v1.vert.qsb"));
QVERIFY(s0.isValid());
+ QCOMPARE(QShaderPrivate::get(&s0)->qsbVersion, 1);
QCOMPARE(s0.availableShaders().count(), 1);
QVERIFY(s0.availableShaders().contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
@@ -229,5 +241,159 @@ void tst_QShader::bakedShaderImplicitSharing()
}
}
+void tst_QShader::mslResourceMapping()
+{
+ QShader s = getShader(QLatin1String(":/data/texture_all_v2.frag.qsb"));
+ QVERIFY(s.isValid());
+ QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 2);
+
+ const QVector<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 QShader::NativeResourceBindingMap *resMap =
+ s.nativeResourceBindingMap(QShaderKey(QShader::GlslShader, QShaderVersion(330)));
+ QVERIFY(!resMap);
+
+ // 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);
+
+ 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 QVector<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, QLatin1String("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, QLatin1String("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, 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("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, QLatin1String("opacity"));
+ QCOMPARE(v.type, QShaderDescription::Float);
+ break;
+ default:
+ QVERIFY(false);
+ break;
+ }
+ }
+}
+
+void tst_QShader::serializeShaderDesc()
+{
+ // default constructed QShaderDescription
+ {
+ QShaderDescription desc;
+ QVERIFY(!desc.isValid());
+
+ const QByteArray data = desc.toCbor();
+ QVERIFY(!data.isEmpty());
+
+ QShaderDescription desc2 = QShaderDescription::fromCbor(data);
+ QVERIFY(!desc2.isValid());
+ }
+
+ // a QShaderDescription with inputs, outputs, uniform block and combined image sampler
+ {
+ QShader s = getShader(QLatin1String(":/data/texture_all_v3.frag.qsb"));
+ QVERIFY(s.isValid());
+ const QShaderDescription desc = s.description();
+ QVERIFY(desc.isValid());
+
+ const QByteArray data = desc.toCbor();
+ QVERIFY(!data.isEmpty());
+
+ QShaderDescription desc2;
+ QVERIFY(!desc2.isValid());
+ QVERIFY(!(desc == desc2));
+ QVERIFY(desc != desc2);
+
+ desc2 = QShaderDescription::fromCbor(data);
+ QVERIFY(desc2.isValid());
+ QCOMPARE(desc, desc2);
+ }
+
+ // exercise QShader and QShaderDescription comparisons
+ {
+ QShader s1 = getShader(QLatin1String(":/data/texture_all_v3.frag.qsb"));
+ QVERIFY(s1.isValid());
+ QShader s2 = getShader(QLatin1String(":/data/color_all_v1.vert.qsb"));
+ QVERIFY(s2.isValid());
+
+ QVERIFY(s1.description().isValid());
+ QVERIFY(s2.description().isValid());
+
+ QVERIFY(s1 != s2);
+ QVERIFY(s1.description() != s2.description());
+ }
+}
+
#include <tst_qshader.moc>
QTEST_MAIN(tst_QShader)