Store a native resource binding map in QShader
The deserializer remains compatible with .qsb files without this additional section. Task-number: QTBUG-79368 Change-Id: I03e2a634febbd88da7f6a4369f104855ea31e3af Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
parent
03717be788
commit
6326d1df39
@ -214,7 +214,8 @@ QT_BEGIN_NAMESPACE
|
||||
QShader, it indicates no shader code was found for the requested key.
|
||||
*/
|
||||
|
||||
static const int QSB_VERSION = 1;
|
||||
static const int QSB_VERSION = 2;
|
||||
static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
|
||||
|
||||
/*!
|
||||
Constructs a new, empty (and thus invalid) QShader instance.
|
||||
@ -345,6 +346,14 @@ void QShader::removeShader(const QShaderKey &key)
|
||||
d->shaders.erase(it);
|
||||
}
|
||||
|
||||
static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
|
||||
{
|
||||
*ds << k.source();
|
||||
*ds << k.sourceVersion().version();
|
||||
*ds << k.sourceVersion().flags();
|
||||
*ds << k.sourceVariant();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return a serialized binary version of all the data held by the
|
||||
QShader, suitable for writing to files or other I/O devices.
|
||||
@ -365,18 +374,42 @@ QByteArray QShader::serialized() const
|
||||
ds << d->shaders.count();
|
||||
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
||||
const QShaderKey &k(it.key());
|
||||
ds << k.source();
|
||||
ds << k.sourceVersion().version();
|
||||
ds << k.sourceVersion().flags();
|
||||
ds << k.sourceVariant();
|
||||
writeShaderKey(&ds, k);
|
||||
const QShaderCode &shader(d->shaders.value(k));
|
||||
ds << shader.shader();
|
||||
ds << shader.entryPoint();
|
||||
}
|
||||
ds << d->bindings.count();
|
||||
for (auto it = d->bindings.cbegin(), itEnd = d->bindings.cend(); it != itEnd; ++it) {
|
||||
const QShaderKey &k(it.key());
|
||||
writeShaderKey(&ds, k);
|
||||
const NativeResourceBindingMap &map(it.value());
|
||||
ds << map.count();
|
||||
for (auto mapIt = map.cbegin(), mapItEnd = map.cend(); mapIt != mapItEnd; ++mapIt) {
|
||||
ds << mapIt.key();
|
||||
ds << mapIt.value().first;
|
||||
ds << mapIt.value().second;
|
||||
}
|
||||
}
|
||||
|
||||
return qCompress(buf.buffer());
|
||||
}
|
||||
|
||||
static void readShaderKey(QDataStream *ds, QShaderKey *k)
|
||||
{
|
||||
int intVal;
|
||||
*ds >> intVal;
|
||||
k->setSource(QShader::Source(intVal));
|
||||
QShaderVersion ver;
|
||||
*ds >> intVal;
|
||||
ver.setVersion(intVal);
|
||||
*ds >> intVal;
|
||||
ver.setFlags(QShaderVersion::Flags(intVal));
|
||||
k->setSourceVersion(ver);
|
||||
*ds >> intVal;
|
||||
k->setSourceVariant(QShader::Variant(intVal));
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates a new QShader instance from the given \a data.
|
||||
|
||||
@ -396,8 +429,11 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
||||
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
|
||||
int intVal;
|
||||
ds >> intVal;
|
||||
if (intVal != QSB_VERSION)
|
||||
const int qsbVersion = intVal;
|
||||
if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
|
||||
qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion);
|
||||
return QShader();
|
||||
}
|
||||
|
||||
ds >> intVal;
|
||||
d->stage = Stage(intVal);
|
||||
@ -408,16 +444,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
||||
ds >> count;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
QShaderKey k;
|
||||
ds >> intVal;
|
||||
k.setSource(Source(intVal));
|
||||
QShaderVersion ver;
|
||||
ds >> intVal;
|
||||
ver.setVersion(intVal);
|
||||
ds >> intVal;
|
||||
ver.setFlags(QShaderVersion::Flags(intVal));
|
||||
k.setSourceVersion(ver);
|
||||
ds >> intVal;
|
||||
k.setSourceVariant(Variant(intVal));
|
||||
readShaderKey(&ds, &k);
|
||||
QShaderCode shader;
|
||||
QByteArray s;
|
||||
ds >> s;
|
||||
@ -427,6 +454,27 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
||||
d->shaders[k] = shader;
|
||||
}
|
||||
|
||||
if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
|
||||
ds >> count;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
QShaderKey k;
|
||||
readShaderKey(&ds, &k);
|
||||
NativeResourceBindingMap map;
|
||||
int mapSize;
|
||||
ds >> mapSize;
|
||||
for (int b = 0; b < mapSize; ++b) {
|
||||
int binding;
|
||||
ds >> binding;
|
||||
int firstNativeBinding;
|
||||
ds >> firstNativeBinding;
|
||||
int secondNativeBinding;
|
||||
ds >> secondNativeBinding;
|
||||
map.insert(binding, { firstNativeBinding, secondNativeBinding });
|
||||
}
|
||||
d->bindings.insert(k, map);
|
||||
}
|
||||
}
|
||||
|
||||
return bs;
|
||||
}
|
||||
|
||||
@ -460,7 +508,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.d->stage == rhs.d->stage
|
||||
&& lhs.d->shaders == rhs.d->shaders;
|
||||
// do not bother with desc, if the shader code is the same, the description must match too
|
||||
// do not bother with desc and bindings, if the shader code is the same, the description must match too
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -586,4 +634,66 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v)
|
||||
}
|
||||
#endif // QT_NO_DEBUG_STREAM
|
||||
|
||||
/*!
|
||||
\typedef QShader::NativeResourceBindingMap
|
||||
|
||||
Synonym for QHash<int, QPair<int, int>>.
|
||||
|
||||
The resource binding model QRhi assumes is based on SPIR-V. This means that
|
||||
uniform buffers, storage buffers, combined image samplers, and storage
|
||||
images share a common binding point space. The binding numbers in
|
||||
QShaderDescription and QRhiShaderResourceBinding are expected to match the
|
||||
\c binding layout qualifier in the Vulkan-compatible GLSL shader.
|
||||
|
||||
Graphics APIs other than Vulkan may use a resource binding model that is
|
||||
not fully compatible with this. In addition, the generator of the shader
|
||||
code translated from SPIR-V may choose not to take the SPIR-V binding
|
||||
qualifiers into account, for various reasons. (this is the case with the
|
||||
Metal backend of SPIRV-Cross, for example).
|
||||
|
||||
Therefore, a QShader may expose an additional map that describes what the
|
||||
native binding point for a given SPIR-V binding is. The QRhi backends are
|
||||
expected to use this map automatically, as appropriate. The value is a
|
||||
pair, because combined image samplers may map to two native resources (a
|
||||
texture and a sampler) in some shading languages. In that case the second
|
||||
value refers to the sampler.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\return the native binding map for \a key or null if no extra mapping is
|
||||
available, or is not applicable.
|
||||
*/
|
||||
const QShader::NativeResourceBindingMap *QShader::nativeResourceBindingMap(const QShaderKey &key) const
|
||||
{
|
||||
auto it = d->bindings.constFind(key);
|
||||
if (it == d->bindings.cend())
|
||||
return nullptr;
|
||||
|
||||
return &it.value();
|
||||
}
|
||||
|
||||
/*!
|
||||
Stores the given native resource binding \a map associated with \a key.
|
||||
|
||||
\sa nativeResourceBindingMap()
|
||||
*/
|
||||
void QShader::setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map)
|
||||
{
|
||||
detach();
|
||||
d->bindings[key] = map;
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes the native resource binding map for \a key.
|
||||
*/
|
||||
void QShader::removeResourceBindingMap(const QShaderKey &key)
|
||||
{
|
||||
auto it = d->bindings.find(key);
|
||||
if (it == d->bindings.end())
|
||||
return;
|
||||
|
||||
detach();
|
||||
d->bindings.erase(it);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -149,6 +149,11 @@ public:
|
||||
QByteArray serialized() const;
|
||||
static QShader fromSerialized(const QByteArray &data);
|
||||
|
||||
using NativeResourceBindingMap = QHash<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
|
||||
const NativeResourceBindingMap *nativeResourceBindingMap(const QShaderKey &key) const;
|
||||
void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
|
||||
void removeResourceBindingMap(const QShaderKey &key);
|
||||
|
||||
private:
|
||||
QShaderPrivate *d;
|
||||
friend struct QShaderPrivate;
|
||||
|
@ -66,7 +66,8 @@ struct Q_GUI_EXPORT QShaderPrivate
|
||||
: ref(1),
|
||||
stage(other->stage),
|
||||
desc(other->desc),
|
||||
shaders(other->shaders)
|
||||
shaders(other->shaders),
|
||||
bindings(other->bindings)
|
||||
{
|
||||
}
|
||||
|
||||
@ -77,6 +78,7 @@ struct Q_GUI_EXPORT QShaderPrivate
|
||||
QShader::Stage stage = QShader::VertexStage;
|
||||
QShaderDescription desc;
|
||||
QHash<QShaderKey, QShaderCode> shaders;
|
||||
QHash<QShaderKey, QShader::NativeResourceBindingMap> bindings;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
Loading…
Reference in New Issue
Block a user