rhi: Enable serializing a layout description without baking an srb

Pick-to: 6.2
Change-Id: I66d28cc9d5417bcd5d192fa100c21f69fd42fd6b
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2021-09-06 18:06:33 +02:00
parent b6b0c33058
commit 4cde0e484c
3 changed files with 40 additions and 10 deletions

View File

@ -2996,7 +2996,7 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi) QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi)
: QRhiResource(rhi) : QRhiResource(rhi)
{ {
m_layoutDesc.reserve(BINDING_PREALLOC * LAYOUT_DESC_FIELD_COUNT); m_layoutDesc.reserve(BINDING_PREALLOC * QRhiShaderResourceBinding::LAYOUT_DESC_ENTRIES_PER_BINDING);
} }
/*! /*!
@ -3047,13 +3047,12 @@ void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
{ {
srb->m_layoutDescHash = 0; srb->m_layoutDescHash = 0;
srb->m_layoutDesc.clear(); srb->m_layoutDesc.clear();
auto layoutDescAppender = std::back_inserter(srb->m_layoutDesc);
for (const QRhiShaderResourceBinding &b : qAsConst(srb->m_bindings)) { for (const QRhiShaderResourceBinding &b : qAsConst(srb->m_bindings)) {
const QRhiShaderResourceBinding::Data *d = b.data(); const QRhiShaderResourceBinding::Data *d = b.data();
// the logic must match QRhiShaderResourceBinding::isLayoutCompatible() srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type)
const int count = d->type == QRhiShaderResourceBinding::SampledTexture ? d->u.stex.count : 1; ^ uint(d->type == QRhiShaderResourceBinding::SampledTexture ? d->u.stex.count : 1);
// the number of entries here should match LAYOUT_DESC_FIELD_COUNT d->serialize(layoutDescAppender);
srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type) ^ uint(count);
srb->m_layoutDesc << uint(d->binding) << uint(d->stage) << uint(d->type) << uint(count);
} }
} }

View File

@ -411,11 +411,34 @@ public:
StorageImageData simage; StorageImageData simage;
StorageBufferData sbuf; StorageBufferData sbuf;
} u; } u;
template<typename Output>
void serialize(Output dst) const
{
// must write out exactly LAYOUT_DESC_ENTRIES_PER_BINDING elements here
*dst++ = quint32(binding);
*dst++ = quint32(stage);
*dst++ = quint32(type);
*dst++ = quint32(type == QRhiShaderResourceBinding::SampledTexture ? u.stex.count : 1);
}
}; };
Data *data() { return &d; } Data *data() { return &d; }
const Data *data() const { return &d; } const Data *data() const { return &d; }
static const int LAYOUT_DESC_ENTRIES_PER_BINDING = 4;
template<typename Output>
static void serializeLayoutDescription(const QRhiShaderResourceBinding *first,
const QRhiShaderResourceBinding *last,
Output dst)
{
while (first != last) {
first->data()->serialize(dst);
++first;
}
}
private: private:
Data d; Data d;
}; };
@ -1037,7 +1060,7 @@ public:
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const; bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
QVector<uint> serializedLayoutDescription() const { return m_layoutDesc; } QVector<quint32> serializedLayoutDescription() const { return m_layoutDesc; }
virtual bool create() = 0; virtual bool create() = 0;
@ -1050,14 +1073,13 @@ public:
protected: protected:
static const int BINDING_PREALLOC = 12; static const int BINDING_PREALLOC = 12;
static const int LAYOUT_DESC_FIELD_COUNT = 4;
QRhiShaderResourceBindings(QRhiImplementation *rhi); QRhiShaderResourceBindings(QRhiImplementation *rhi);
QVarLengthArray<QRhiShaderResourceBinding, BINDING_PREALLOC> m_bindings; QVarLengthArray<QRhiShaderResourceBinding, BINDING_PREALLOC> m_bindings;
uint m_layoutDescHash = 0; size_t m_layoutDescHash = 0;
// Intentionally not using QVLA for m_layoutDesc: clients like Qt Quick are much // Intentionally not using QVLA for m_layoutDesc: clients like Qt Quick are much
// better served with an implicitly shared container here, because they will likely // better served with an implicitly shared container here, because they will likely
// throw this directly into structs serving as cache keys. // throw this directly into structs serving as cache keys.
QVector<uint> m_layoutDesc; QVector<quint32> m_layoutDesc;
friend class QRhiImplementation; friend class QRhiImplementation;
#ifndef QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &); friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);

View File

@ -3314,6 +3314,15 @@ void tst_QRhi::srbLayoutCompatibility()
QVERIFY(!srb1->serializedLayoutDescription().isEmpty()); QVERIFY(!srb1->serializedLayoutDescription().isEmpty());
QVERIFY(!srb2->serializedLayoutDescription().isEmpty()); QVERIFY(!srb2->serializedLayoutDescription().isEmpty());
QCOMPARE(srb1->serializedLayoutDescription(), srb2->serializedLayoutDescription()); QCOMPARE(srb1->serializedLayoutDescription(), srb2->serializedLayoutDescription());
// see what we would get if a binding list got serialized "manually", without pulling it out from the srb after building
// (the results should be identical)
QVector<quint32> layoutDesc1;
QRhiShaderResourceBinding::serializeLayoutDescription(srb1->cbeginBindings(), srb1->cendBindings(), std::back_inserter(layoutDesc1));
QCOMPARE(layoutDesc1, srb1->serializedLayoutDescription());
QVector<quint32> layoutDesc2;
QRhiShaderResourceBinding::serializeLayoutDescription(srb2->cbeginBindings(), srb2->cendBindings(), std::back_inserter(layoutDesc2));
QCOMPARE(layoutDesc2, srb2->serializedLayoutDescription());
} }
// different visibility (not compatible) // different visibility (not compatible)