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>
This commit is contained in:
parent
2fe3b0e564
commit
0943b5d65d
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 &);
|
||||
|
BIN
tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb
Normal file
BIN
tests/auto/gui/rhi/qshader/data/storage_buffer_info_v8.comp.qsb
Normal file
Binary file not shown.
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user