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
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()
*/
QByteArray QShader::serialized() const
QByteArray QShader::serialized(SerializedFormatVersion version) const
{
static QShaderPrivate sd;
QShaderPrivate *dd = d ? d : &sd;
@ -378,9 +381,11 @@ QByteArray QShader::serialized() const
if (!buf.open(QIODevice::WriteOnly))
return QByteArray();
ds << QShaderPrivate::QSB_VERSION;
const int qsbVersion = QShaderPrivate::qtQsbVersion(version);
ds << qsbVersion;
ds << int(dd->stage);
dd->desc.serialize(&ds);
dd->desc.serialize(&ds, qsbVersion);
ds << int(dd->shaders.size());
for (auto it = dd->shaders.cbegin(), itEnd = dd->shaders.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
@ -413,17 +418,19 @@ QByteArray QShader::serialized() const
ds << listIt->samplerBinding;
}
}
ds << int(dd->nativeShaderInfoMap.size());
for (auto it = dd->nativeShaderInfoMap.cbegin(), itEnd = dd->nativeShaderInfoMap.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
writeShaderKey(&ds, k);
ds << it->flags;
ds << int(it->extraBufferBindings.size());
for (auto mapIt = it->extraBufferBindings.cbegin(), mapItEnd = it->extraBufferBindings.cend();
mapIt != mapItEnd; ++mapIt)
{
ds << mapIt.key();
ds << mapIt.value();
if (qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
ds << int(dd->nativeShaderInfoMap.size());
for (auto it = dd->nativeShaderInfoMap.cbegin(), itEnd = dd->nativeShaderInfoMap.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
writeShaderKey(&ds, k);
ds << it->flags;
ds << int(it->extraBufferBindings.size());
for (auto mapIt = it->extraBufferBindings.cbegin(), mapItEnd = it->extraBufferBindings.cend();
mapIt != mapItEnd; ++mapIt)
{
ds << mapIt.key();
ds << mapIt.value();
}
}
}

View File

@ -110,6 +110,12 @@ public:
NonIndexedVertexAsComputeShader
};
enum class SerializedFormatVersion {
Latest = 0,
Qt_6_5,
Qt_6_4
};
QShader();
QShader(const QShader &other);
QShader &operator=(const QShader &other);
@ -129,7 +135,7 @@ public:
void setShader(const QShaderKey &key, const QShaderCode &shader);
void removeShader(const QShaderKey &key);
QByteArray serialized() const;
QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
static QShader fromSerialized(const QByteArray &data);
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 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;
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()
*/
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.binding;
@ -1077,7 +1078,8 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription::
(*stream) << int(v.arrayDims.size());
for (int dim : v.arrayDims)
(*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)
@ -1089,11 +1091,11 @@ static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
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) << int(v.type);
serializeDecorations(stream, v);
serializeDecorations(stream, v, version);
}
static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
@ -1297,15 +1299,15 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
return QJsonDocument(root);
}
void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
void QShaderDescriptionPrivate::writeToStream(QDataStream *stream, int version)
{
(*stream) << int(inVars.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(inVars))
serializeInOutVar(stream, v);
serializeInOutVar(stream, v, version);
(*stream) << int(outVars.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(outVars))
serializeInOutVar(stream, v);
serializeInOutVar(stream, v, version);
(*stream) << int(uniformBlocks.size());
for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
@ -1338,22 +1340,24 @@ void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
(*stream) << int(b.members.size());
for (const QShaderDescription::BlockVariable &v : b.members)
serializeBlockMemberVar(stream, v);
(*stream) << b.runtimeArrayStride;
(*stream) << b.qualifierFlags;
if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) {
(*stream) << b.runtimeArrayStride;
(*stream) << b.qualifierFlags;
}
}
(*stream) << int(combinedImageSamplers.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(combinedImageSamplers)) {
(*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type);
serializeDecorations(stream, v);
serializeDecorations(stream, v, version);
}
(*stream) << int(storageImages.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(storageImages)) {
(*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type);
serializeDecorations(stream, v);
serializeDecorations(stream, v, version);
}
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)) {
(*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type);
serializeDecorations(stream, v);
serializeDecorations(stream, v, version);
}
(*stream) << int(separateSamplers.size());
for (const QShaderDescription::InOutVariable &v : std::as_const(separateSamplers)) {
(*stream) << QString::fromUtf8(v.name);
(*stream) << int(v.type);
serializeDecorations(stream, v);
serializeDecorations(stream, v, version);
}
(*stream) << quint32(tessOutVertCount);
(*stream) << quint32(tessMode);
(*stream) << quint32(tessWind);
(*stream) << quint32(tessPart);
if (version > QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO) {
(*stream) << quint32(tessOutVertCount);
(*stream) << quint32(tessMode);
(*stream) << quint32(tessWind);
(*stream) << quint32(tessPart);
(*stream) << int(inBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins))
(*stream) << int(v.type);
(*stream) << int(inBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(inBuiltins))
(*stream) << int(v.type);
(*stream) << int(outBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins))
(*stream) << int(v.type);
(*stream) << int(outBuiltins.size());
for (const QShaderDescription::BuiltinVariable &v : std::as_const(outBuiltins))
(*stream) << int(v.type);
}
}
static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v)

View File

@ -37,7 +37,7 @@ public:
bool isValid() const;
void serialize(QDataStream *stream) const;
void serialize(QDataStream *stream, int version) const;
QByteArray toJson() const;
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; }
QJsonDocument makeDoc();
void writeToStream(QDataStream *stream);
void writeToStream(QDataStream *stream, int version);
void loadFromStream(QDataStream *stream, int version);
QAtomicInt ref;

View File

@ -294,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());
@ -319,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());