diff options
author | Ben Fletcher <ben.fletcher@me.com> | 2022-12-06 19:52:59 -0800 |
---|---|---|
committer | Ben Fletcher <ben.fletcher@me.com> | 2022-12-11 11:05:24 -0800 |
commit | 0943b5d65d1a5699fb2085f4d92c9112fb08871d (patch) | |
tree | 35fd67535171a6683809149a541b3718b7d0e4b3 | |
parent | 2fe3b0e5640df34d5512e06ecbc5739c2d4df21e (diff) |
RHI: QShaderDescription storage buffer qualifiers / run time stride
Add storage buffer memory qualifier and run time array stride information
to QShaderDescription::StorageBlock.
Memory qualifiers allow more informed selection of RHI resource buffer
binding (bufferLoad / bufferStore / bufferLoadStore) function.
Run time array stride (for last block member unsized array) allows
packing of buffer data for transfer to / from GPU. Without this
information, applications must infer or guess which packing rules
(std430 / std140) are in use.
Change-Id: I676d7e848afefd40d01cdd463c569b07022b683e
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r-- | src/gui/rhi/qshader.cpp | 1 | ||||
-rw-r--r-- | src/gui/rhi/qshader_p_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qshaderdescription.cpp | 25 | ||||
-rw-r--r-- | src/gui/rhi/qshaderdescription_p.h | 12 | ||||
-rw-r--r-- | tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb | bin | 0 -> 902 bytes | |||
-rw-r--r-- | tests/auto/gui/rhi/qshader/tst_qshader.cpp | 23 |
6 files changed, 62 insertions, 2 deletions
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index e27ac8365e..440e7fedc8 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -467,6 +467,7 @@ QShader QShader::fromSerialized(const QByteArray &data) ds >> intVal; d->qsbVersion = intVal; if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 88406b1ea2..b0ba04ef51 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -24,7 +24,8 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { - static const int QSB_VERSION = 7; + static const int QSB_VERSION = 8; + static const int QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO = 7; static const int QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO = 6; static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5; static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 387ebc7c53..443900240a 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -403,6 +403,7 @@ QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlo "blockName": "StuffSsbo", "instanceName": "buf", "knownSize": 16, + "runtimeArrayStride": 16 "members": [ { "name": "whatever", @@ -440,7 +441,10 @@ QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlo \note The size of the last member in the storage block is undefined. This shows up as \c size 0 and an array dimension of \c{[0]}. The storage block's \c knownSize - excludes the size of the last member since that will only be known at run time. + excludes the size of the last member since that will only be known at run time. The + stride in bytes between array items for a last member with undefined array size is + \c runtimeArrayStride. This value is determined according to the specified buffer + memory layout standard (std140, std430) rules. \note SSBOs are not available with some graphics APIs, such as, OpenGL 2.x or OpenGL ES older than 3.1. @@ -984,6 +988,10 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk) dbg.nospace() << " binding=" << blk.binding; if (blk.descriptorSet >= 0) dbg.nospace() << " set=" << blk.descriptorSet; + if (blk.runtimeArrayStride) + dbg.nospace() << " runtimeArrayStride=" << blk.runtimeArrayStride; + if (blk.qualifierFlags) + dbg.nospace() << " qualifierFlags=" << blk.qualifierFlags; dbg.nospace() << ' ' << blk.members << ')'; return dbg; } @@ -1033,6 +1041,8 @@ JSON_KEY(tessellationWindingOrder) JSON_KEY(tessellationPartitioning) JSON_KEY(separateImages) JSON_KEY(separateSamplers) +JSON_KEY(runtimeArrayStride) +JSON_KEY(qualifierFlags) #undef JSON_KEY static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v) @@ -1190,6 +1200,10 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc() jstorageBlock[bindingKey()] = b.binding; if (b.descriptorSet >= 0) jstorageBlock[setKey()] = b.descriptorSet; + if (b.runtimeArrayStride) + jstorageBlock[runtimeArrayStrideKey()] = b.runtimeArrayStride; + if (b.qualifierFlags) + jstorageBlock[qualifierFlagsKey()] = int(b.qualifierFlags); QJsonArray members; for (const QShaderDescription::BlockVariable &v : b.members) members.append(blockMemberObject(v)); @@ -1324,6 +1338,8 @@ 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; } (*stream) << int(combinedImageSamplers.size()); @@ -1498,6 +1514,11 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version) storageBlocks[i].members.resize(memberCount); for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx) storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version); + + if (version > QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO) { + (*stream) >> storageBlocks[i].runtimeArrayStride; + (*stream) >> storageBlocks[i].qualifierFlags; + } } (*stream) >> count; @@ -1694,6 +1715,8 @@ bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescri && lhs.knownSize == rhs.knownSize && lhs.binding == rhs.binding && lhs.descriptorSet == rhs.descriptorSet + && lhs.runtimeArrayStride == rhs.runtimeArrayStride + && lhs.qualifierFlags == rhs.qualifierFlags && lhs.members == rhs.members; } diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index df4e8fd873..7e5412a784 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -170,6 +170,15 @@ public: }; Q_DECLARE_FLAGS(ImageFlags, ImageFlag) + enum QualifierFlag { + QualifierReadOnly = 1 << 0, + QualifierWriteOnly = 1 << 1, + QualifierCoherent = 1 << 2, + QualifierVolatile = 1 << 3, + QualifierRestrict = 1 << 4, + }; + Q_DECLARE_FLAGS(QualifierFlags, QualifierFlag) + // Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional. struct InOutVariable { @@ -218,6 +227,8 @@ public: int binding = -1; int descriptorSet = -1; QList<BlockVariable> members; + int runtimeArrayStride = 0; + QualifierFlags qualifierFlags; }; QList<InOutVariable> inputVariables() const; @@ -310,6 +321,7 @@ private: }; Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags) #ifndef QT_NO_DEBUG_STREAM Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &); diff --git a/tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb b/tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb Binary files differnew file mode 100644 index 0000000000..edcd84cbe6 --- /dev/null +++ b/tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index 26ea56b047..52de60ce55 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -26,6 +26,7 @@ private slots: void manualShaderPackCreation(); void loadV6WithSeparateImagesAndSamplers(); void loadV7(); + void loadV8(); }; static QShader getShader(const QString &name) @@ -673,5 +674,27 @@ void tst_QShader::loadV7() 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) |