Support serializing the QShader for qsb version

Support serializing shaders with specific qsb version. The default
behavior remains the same, using the latest version.

Task-number: QTBUG-101062
Pick-to: 6.5
Change-Id: I090a88c1ccb3be4ac5eee1da4058afaa8bf3111c
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Kaj Grönholm 2023-01-03 14:10:04 +02:00 committed by Laszlo Agocs
parent 90751ff13d
commit df00f9ea86
7 changed files with 74 additions and 45 deletions

View File

@ -365,9 +365,12 @@ static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
\return a serialized binary version of all the data held by the \return a serialized binary version of all the data held by the
QShader, suitable for writing to files or other I/O devices. QShader, suitable for writing to files or other I/O devices.
By default the latest serialization format is used. Use \a version
parameter to serialize for a compatibility Qt version.
\sa fromSerialized() \sa fromSerialized()
*/ */
QByteArray QShader::serialized() const QByteArray QShader::serialized(SerializedFormatVersion version) const
{ {
static QShaderPrivate sd; static QShaderPrivate sd;
QShaderPrivate *dd = d ? d : &sd; QShaderPrivate *dd = d ? d : &sd;
@ -378,9 +381,11 @@ QByteArray QShader::serialized() const
if (!buf.open(QIODevice::WriteOnly)) if (!buf.open(QIODevice::WriteOnly))
return QByteArray(); return QByteArray();
ds << QShaderPrivate::QSB_VERSION; const int qsbVersion = QShaderPrivate::qtQsbVersion(version);
ds << qsbVersion;
ds << int(dd->stage); ds << int(dd->stage);
dd->desc.serialize(&ds); dd->desc.serialize(&ds, qsbVersion);
ds << int(dd->shaders.size()); ds << int(dd->shaders.size());
for (auto it = dd->shaders.cbegin(), itEnd = dd->shaders.cend(); it != itEnd; ++it) { for (auto it = dd->shaders.cbegin(), itEnd = dd->shaders.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key()); const QShaderKey &k(it.key());
@ -413,17 +418,19 @@ QByteArray QShader::serialized() const
ds << listIt->samplerBinding; ds << listIt->samplerBinding;
} }
} }
ds << int(dd->nativeShaderInfoMap.size()); if (qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
for (auto it = dd->nativeShaderInfoMap.cbegin(), itEnd = dd->nativeShaderInfoMap.cend(); it != itEnd; ++it) { ds << int(dd->nativeShaderInfoMap.size());
const QShaderKey &k(it.key()); for (auto it = dd->nativeShaderInfoMap.cbegin(), itEnd = dd->nativeShaderInfoMap.cend(); it != itEnd; ++it) {
writeShaderKey(&ds, k); const QShaderKey &k(it.key());
ds << it->flags; writeShaderKey(&ds, k);
ds << int(it->extraBufferBindings.size()); ds << it->flags;
for (auto mapIt = it->extraBufferBindings.cbegin(), mapItEnd = it->extraBufferBindings.cend(); ds << int(it->extraBufferBindings.size());
mapIt != mapItEnd; ++mapIt) for (auto mapIt = it->extraBufferBindings.cbegin(), mapItEnd = it->extraBufferBindings.cend();
{ mapIt != mapItEnd; ++mapIt)
ds << mapIt.key(); {
ds << mapIt.value(); ds << mapIt.key();
ds << mapIt.value();
}
} }
} }

View File

@ -110,6 +110,12 @@ public:
NonIndexedVertexAsComputeShader NonIndexedVertexAsComputeShader
}; };
enum class SerializedFormatVersion {
Latest = 0,
Qt_6_5,
Qt_6_4
};
QShader(); QShader();
QShader(const QShader &other); QShader(const QShader &other);
QShader &operator=(const QShader &other); QShader &operator=(const QShader &other);
@ -129,7 +135,7 @@ public:
void setShader(const QShaderKey &key, const QShaderCode &shader); void setShader(const QShaderKey &key, const QShaderCode &shader);
void removeShader(const QShaderKey &key); void removeShader(const QShaderKey &key);
QByteArray serialized() const; QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
static QShader fromSerialized(const QByteArray &data); static QShader fromSerialized(const QByteArray &data);
using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding] using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding]

View File

@ -61,6 +61,16 @@ struct Q_GUI_EXPORT QShaderPrivate
static QShaderPrivate *get(QShader *s) { return s->d; } static QShaderPrivate *get(QShader *s) { return s->d; }
static const QShaderPrivate *get(const QShader *s) { return s->d; } static const QShaderPrivate *get(const QShader *s) { return s->d; }
static int qtQsbVersion(QShader::SerializedFormatVersion qtVersion) {
switch (qtVersion) {
case QShader::SerializedFormatVersion::Qt_6_4:
return (QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS + 1);
case QShader::SerializedFormatVersion::Qt_6_5:
return (QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO + 1);
default:
return QShaderPrivate::QSB_VERSION;
}
}
QAtomicInt ref; QAtomicInt ref;
int qsbVersion = QSB_VERSION; int qsbVersion = QSB_VERSION;

View File

@ -319,13 +319,14 @@ QByteArray QShaderDescription::toJson() const
} }
/*! /*!
Serializes this QShaderDescription to \a stream. Serializes this QShaderDescription to \a stream. \a version specifies
the qsb version.
\sa deserialize(), toJson() \sa deserialize(), toJson()
*/ */
void QShaderDescription::serialize(QDataStream *stream) const void QShaderDescription::serialize(QDataStream *stream, int version) const
{ {
d->writeToStream(stream); d->writeToStream(stream, version);
} }
/*! /*!
@ -1067,7 +1068,7 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v
} }
} }
static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v) static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v, int version)
{ {
(*stream) << v.location; (*stream) << v.location;
(*stream) << v.binding; (*stream) << v.binding;
@ -1077,7 +1078,8 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription::
(*stream) << int(v.arrayDims.size()); (*stream) << int(v.arrayDims.size());
for (int dim : v.arrayDims) for (int dim : v.arrayDims)
(*stream) << dim; (*stream) << dim;
(*stream) << quint8(v.perPatch); if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO)
(*stream) << quint8(v.perPatch);
} }
static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v) static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
@ -1089,11 +1091,11 @@ static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
return obj; return obj;
} }
static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v) static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v, int version)
{ {
(*stream) << QString::fromUtf8(v.name); (*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type); (*stream) << int(v.type);
serializeDecorations(stream, v); serializeDecorations(stream, v, version);
} }
static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v) static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
@ -1297,15 +1299,15 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
return QJsonDocument(root); return QJsonDocument(root);
} }
void QShaderDescriptionPrivate::writeToStream(QDataStream *stream) void QShaderDescriptionPrivate::writeToStream(QDataStream *stream, int version)
{ {
(*stream) << int(inVars.size()); (*stream) << int(inVars.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(inVars)) for (const QShaderDescription::InOutVariable &v : std::as_const(inVars))
serializeInOutVar(stream, v); serializeInOutVar(stream, v, version);
(*stream) << int(outVars.size()); (*stream) << int(outVars.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(outVars)) for (const QShaderDescription::InOutVariable &v : std::as_const(outVars))
serializeInOutVar(stream, v); serializeInOutVar(stream, v, version);
(*stream) << int(uniformBlocks.size()); (*stream) << int(uniformBlocks.size());
for (const QShaderDescription::UniformBlock &b : uniformBlocks) { for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
@ -1338,22 +1340,24 @@ void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
(*stream) << int(b.members.size()); (*stream) << int(b.members.size());
for (const QShaderDescription::BlockVariable &v : b.members) for (const QShaderDescription::BlockVariable &v : b.members)
serializeBlockMemberVar(stream, v); serializeBlockMemberVar(stream, v);
(*stream) << b.runtimeArrayStride; if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) {
(*stream) << b.qualifierFlags; (*stream) << b.runtimeArrayStride;
(*stream) << b.qualifierFlags;
}
} }
(*stream) << int(combinedImageSamplers.size()); (*stream) << int(combinedImageSamplers.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(combinedImageSamplers)) { for (const QShaderDescription::InOutVariable &v : std::as_const(combinedImageSamplers)) {
(*stream) << QString::fromUtf8(v.name); (*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type); (*stream) << int(v.type);
serializeDecorations(stream, v); serializeDecorations(stream, v, version);
} }
(*stream) << int(storageImages.size()); (*stream) << int(storageImages.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(storageImages)) { for (const QShaderDescription::InOutVariable &v : std::as_const(storageImages)) {
(*stream) << QString::fromUtf8(v.name); (*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type); (*stream) << int(v.type);
serializeDecorations(stream, v); serializeDecorations(stream, v, version);
} }
for (size_t i = 0; i < 3; ++i) for (size_t i = 0; i < 3; ++i)
@ -1363,28 +1367,30 @@ void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
for (const QShaderDescription::InOutVariable &v : std::as_const(separateImages)) { for (const QShaderDescription::InOutVariable &v : std::as_const(separateImages)) {
(*stream) << QString::fromUtf8(v.name); (*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type); (*stream) << int(v.type);
serializeDecorations(stream, v); serializeDecorations(stream, v, version);
} }
(*stream) << int(separateSamplers.size()); (*stream) << int(separateSamplers.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(separateSamplers)) { for (const QShaderDescription::InOutVariable &v : std::as_const(separateSamplers)) {
(*stream) << QString::fromUtf8(v.name); (*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type); (*stream) << int(v.type);
serializeDecorations(stream, v); serializeDecorations(stream, v, version);
} }
(*stream) << quint32(tessOutVertCount); if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
(*stream) << quint32(tessMode); (*stream) << quint32(tessOutVertCount);
(*stream) << quint32(tessWind); (*stream) << quint32(tessMode);
(*stream) << quint32(tessPart); (*stream) << quint32(tessWind);
(*stream) << quint32(tessPart);
(*stream) << int(inBuiltins.size()); (*stream) << int(inBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins)) for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins))
(*stream) << int(v.type); (*stream) << int(v.type);
(*stream) << int(outBuiltins.size()); (*stream) << int(outBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins)) for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins))
(*stream) << int(v.type); (*stream) << int(v.type);
}
} }
static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v) static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v)

View File

@ -37,7 +37,7 @@ public:
bool isValid() const; bool isValid() const;
void serialize(QDataStream *stream) const; void serialize(QDataStream *stream, int version) const;
QByteArray toJson() const; QByteArray toJson() const;
static QShaderDescription deserialize(QDataStream *stream, int version); static QShaderDescription deserialize(QDataStream *stream, int version);

View File

@ -54,7 +54,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; } static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
QJsonDocument makeDoc(); QJsonDocument makeDoc();
void writeToStream(QDataStream *stream); void writeToStream(QDataStream *stream, int version);
void loadFromStream(QDataStream *stream, int version); void loadFromStream(QDataStream *stream, int version);
QAtomicInt ref; QAtomicInt ref;

View File

@ -294,7 +294,7 @@ void tst_QShader::serializeShaderDesc()
QBuffer buf(&data); QBuffer buf(&data);
QDataStream ds(&buf); QDataStream ds(&buf);
QVERIFY(buf.open(QIODevice::WriteOnly)); QVERIFY(buf.open(QIODevice::WriteOnly));
desc.serialize(&ds); desc.serialize(&ds, QShaderPrivate::QSB_VERSION);
} }
QVERIFY(!data.isEmpty()); QVERIFY(!data.isEmpty());
@ -319,7 +319,7 @@ void tst_QShader::serializeShaderDesc()
QBuffer buf(&data); QBuffer buf(&data);
QDataStream ds(&buf); QDataStream ds(&buf);
QVERIFY(buf.open(QIODevice::WriteOnly)); QVERIFY(buf.open(QIODevice::WriteOnly));
desc.serialize(&ds); desc.serialize(&ds, QShaderPrivate::QSB_VERSION);
} }
QVERIFY(!data.isEmpty()); QVERIFY(!data.isEmpty());