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;
|
ds >> intVal;
|
||||||
d->qsbVersion = intVal;
|
d->qsbVersion = intVal;
|
||||||
if (d->qsbVersion != QShaderPrivate::QSB_VERSION
|
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_NATIVE_SHADER_INFO
|
||||||
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS
|
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS
|
||||||
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS
|
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS
|
||||||
|
@ -24,7 +24,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
struct Q_GUI_EXPORT QShaderPrivate
|
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_NATIVE_SHADER_INFO = 6;
|
||||||
static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
|
static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
|
||||||
static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
|
static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
|
||||||
|
@ -403,6 +403,7 @@ QList<QShaderDescription::PushConstantBlock> QShaderDescription::pushConstantBlo
|
|||||||
"blockName": "StuffSsbo",
|
"blockName": "StuffSsbo",
|
||||||
"instanceName": "buf",
|
"instanceName": "buf",
|
||||||
"knownSize": 16,
|
"knownSize": 16,
|
||||||
|
"runtimeArrayStride": 16
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"name": "whatever",
|
"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
|
\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
|
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
|
\note SSBOs are not available with some graphics APIs, such as, OpenGL 2.x or
|
||||||
OpenGL ES older than 3.1.
|
OpenGL ES older than 3.1.
|
||||||
@ -984,6 +988,10 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::StorageBlock &blk)
|
|||||||
dbg.nospace() << " binding=" << blk.binding;
|
dbg.nospace() << " binding=" << blk.binding;
|
||||||
if (blk.descriptorSet >= 0)
|
if (blk.descriptorSet >= 0)
|
||||||
dbg.nospace() << " set=" << blk.descriptorSet;
|
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 << ')';
|
dbg.nospace() << ' ' << blk.members << ')';
|
||||||
return dbg;
|
return dbg;
|
||||||
}
|
}
|
||||||
@ -1033,6 +1041,8 @@ JSON_KEY(tessellationWindingOrder)
|
|||||||
JSON_KEY(tessellationPartitioning)
|
JSON_KEY(tessellationPartitioning)
|
||||||
JSON_KEY(separateImages)
|
JSON_KEY(separateImages)
|
||||||
JSON_KEY(separateSamplers)
|
JSON_KEY(separateSamplers)
|
||||||
|
JSON_KEY(runtimeArrayStride)
|
||||||
|
JSON_KEY(qualifierFlags)
|
||||||
#undef JSON_KEY
|
#undef JSON_KEY
|
||||||
|
|
||||||
static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
|
static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
|
||||||
@ -1190,6 +1200,10 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
|
|||||||
jstorageBlock[bindingKey()] = b.binding;
|
jstorageBlock[bindingKey()] = b.binding;
|
||||||
if (b.descriptorSet >= 0)
|
if (b.descriptorSet >= 0)
|
||||||
jstorageBlock[setKey()] = b.descriptorSet;
|
jstorageBlock[setKey()] = b.descriptorSet;
|
||||||
|
if (b.runtimeArrayStride)
|
||||||
|
jstorageBlock[runtimeArrayStrideKey()] = b.runtimeArrayStride;
|
||||||
|
if (b.qualifierFlags)
|
||||||
|
jstorageBlock[qualifierFlagsKey()] = int(b.qualifierFlags);
|
||||||
QJsonArray members;
|
QJsonArray members;
|
||||||
for (const QShaderDescription::BlockVariable &v : b.members)
|
for (const QShaderDescription::BlockVariable &v : b.members)
|
||||||
members.append(blockMemberObject(v));
|
members.append(blockMemberObject(v));
|
||||||
@ -1324,6 +1338,8 @@ 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;
|
||||||
|
(*stream) << b.qualifierFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*stream) << int(combinedImageSamplers.size());
|
(*stream) << int(combinedImageSamplers.size());
|
||||||
@ -1498,6 +1514,11 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version)
|
|||||||
storageBlocks[i].members.resize(memberCount);
|
storageBlocks[i].members.resize(memberCount);
|
||||||
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
|
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
|
||||||
storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
|
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;
|
(*stream) >> count;
|
||||||
@ -1694,6 +1715,8 @@ bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescri
|
|||||||
&& lhs.knownSize == rhs.knownSize
|
&& lhs.knownSize == rhs.knownSize
|
||||||
&& lhs.binding == rhs.binding
|
&& lhs.binding == rhs.binding
|
||||||
&& lhs.descriptorSet == rhs.descriptorSet
|
&& lhs.descriptorSet == rhs.descriptorSet
|
||||||
|
&& lhs.runtimeArrayStride == rhs.runtimeArrayStride
|
||||||
|
&& lhs.qualifierFlags == rhs.qualifierFlags
|
||||||
&& lhs.members == rhs.members;
|
&& lhs.members == rhs.members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +170,15 @@ public:
|
|||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(ImageFlags, ImageFlag)
|
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.
|
// Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional.
|
||||||
|
|
||||||
struct InOutVariable {
|
struct InOutVariable {
|
||||||
@ -218,6 +227,8 @@ public:
|
|||||||
int binding = -1;
|
int binding = -1;
|
||||||
int descriptorSet = -1;
|
int descriptorSet = -1;
|
||||||
QList<BlockVariable> members;
|
QList<BlockVariable> members;
|
||||||
|
int runtimeArrayStride = 0;
|
||||||
|
QualifierFlags qualifierFlags;
|
||||||
};
|
};
|
||||||
|
|
||||||
QList<InOutVariable> inputVariables() const;
|
QList<InOutVariable> inputVariables() const;
|
||||||
@ -310,6 +321,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags)
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
|
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 manualShaderPackCreation();
|
||||||
void loadV6WithSeparateImagesAndSamplers();
|
void loadV6WithSeparateImagesAndSamplers();
|
||||||
void loadV7();
|
void loadV7();
|
||||||
|
void loadV8();
|
||||||
};
|
};
|
||||||
|
|
||||||
static QShader getShader(const QString &name)
|
static QShader getShader(const QString &name)
|
||||||
@ -673,5 +674,27 @@ void tst_QShader::loadV7()
|
|||||||
QCOMPARE(QShaderPrivate::get(&frag)->qsbVersion, 7);
|
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>
|
#include <tst_qshader.moc>
|
||||||
QTEST_MAIN(tst_QShader)
|
QTEST_MAIN(tst_QShader)
|
||||||
|
Loading…
Reference in New Issue
Block a user