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.
|
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.
|
Constructs a new, empty (and thus invalid) QShader instance.
|
||||||
@ -345,6 +346,14 @@ void QShader::removeShader(const QShaderKey &key)
|
|||||||
d->shaders.erase(it);
|
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
|
\return a serialized binary version of all the data held by the
|
||||||
QShader, suitable for writing to files or other I/O devices.
|
QShader, suitable for writing to files or other I/O devices.
|
||||||
@ -365,18 +374,42 @@ QByteArray QShader::serialized() const
|
|||||||
ds << d->shaders.count();
|
ds << d->shaders.count();
|
||||||
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
|
||||||
const QShaderKey &k(it.key());
|
const QShaderKey &k(it.key());
|
||||||
ds << k.source();
|
writeShaderKey(&ds, k);
|
||||||
ds << k.sourceVersion().version();
|
|
||||||
ds << k.sourceVersion().flags();
|
|
||||||
ds << k.sourceVariant();
|
|
||||||
const QShaderCode &shader(d->shaders.value(k));
|
const QShaderCode &shader(d->shaders.value(k));
|
||||||
ds << shader.shader();
|
ds << shader.shader();
|
||||||
ds << shader.entryPoint();
|
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());
|
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.
|
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
|
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
|
||||||
int intVal;
|
int intVal;
|
||||||
ds >> 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();
|
return QShader();
|
||||||
|
}
|
||||||
|
|
||||||
ds >> intVal;
|
ds >> intVal;
|
||||||
d->stage = Stage(intVal);
|
d->stage = Stage(intVal);
|
||||||
@ -408,16 +444,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
|||||||
ds >> count;
|
ds >> count;
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
QShaderKey k;
|
QShaderKey k;
|
||||||
ds >> intVal;
|
readShaderKey(&ds, &k);
|
||||||
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));
|
|
||||||
QShaderCode shader;
|
QShaderCode shader;
|
||||||
QByteArray s;
|
QByteArray s;
|
||||||
ds >> s;
|
ds >> s;
|
||||||
@ -427,6 +454,27 @@ QShader QShader::fromSerialized(const QByteArray &data)
|
|||||||
d->shaders[k] = shader;
|
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;
|
return bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +508,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) Q_DECL_NOTHROW
|
|||||||
{
|
{
|
||||||
return lhs.d->stage == rhs.d->stage
|
return lhs.d->stage == rhs.d->stage
|
||||||
&& lhs.d->shaders == rhs.d->shaders;
|
&& 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
|
#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
|
QT_END_NAMESPACE
|
||||||
|
@ -149,6 +149,11 @@ public:
|
|||||||
QByteArray serialized() const;
|
QByteArray serialized() const;
|
||||||
static QShader fromSerialized(const QByteArray &data);
|
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:
|
private:
|
||||||
QShaderPrivate *d;
|
QShaderPrivate *d;
|
||||||
friend struct QShaderPrivate;
|
friend struct QShaderPrivate;
|
||||||
|
@ -66,7 +66,8 @@ struct Q_GUI_EXPORT QShaderPrivate
|
|||||||
: ref(1),
|
: ref(1),
|
||||||
stage(other->stage),
|
stage(other->stage),
|
||||||
desc(other->desc),
|
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;
|
QShader::Stage stage = QShader::VertexStage;
|
||||||
QShaderDescription desc;
|
QShaderDescription desc;
|
||||||
QHash<QShaderKey, QShaderCode> shaders;
|
QHash<QShaderKey, QShaderCode> shaders;
|
||||||
|
QHash<QShaderKey, QShader::NativeResourceBindingMap> bindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
Reference in New Issue
Block a user