rhi: Sanity check the srb in debug builds
Instead of cryptic assertions and crashes depending on the backend, show some useful warnings (in debug builds only) when one tries to create an srb with a list where there are duplicated bindings. (a mistake that happens relatively often during the development of frameworks, such as Quick 3D, on top) Change-Id: If1b50a2e8165b001878ad566e048f146e636514f Reviewed-by: Andy Nichols <andy.nichols@qt.io>bb10
parent
95daeb2407
commit
f6802a5aac
|
|
@ -3400,7 +3400,7 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
|||
<< ')';
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
dbg.nospace() << " UNKNOWN()";
|
||||
break;
|
||||
}
|
||||
dbg.nospace() << ')';
|
||||
|
|
@ -4350,6 +4350,79 @@ bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb)
|
||||
{
|
||||
#ifndef QT_NO_DEBUG
|
||||
bool bindingsOk = true;
|
||||
const int CHECKED_BINDINGS_COUNT = 64;
|
||||
bool bindingSeen[CHECKED_BINDINGS_COUNT] = {};
|
||||
for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) {
|
||||
const int binding = it->data()->binding;
|
||||
if (binding >= CHECKED_BINDINGS_COUNT)
|
||||
continue;
|
||||
if (binding < 0) {
|
||||
qWarning("Invalid binding number %d", binding);
|
||||
bindingsOk = false;
|
||||
continue;
|
||||
}
|
||||
switch (it->data()->type) {
|
||||
case QRhiShaderResourceBinding::UniformBuffer:
|
||||
if (!bindingSeen[binding]) {
|
||||
bindingSeen[binding] = true;
|
||||
} else {
|
||||
qWarning("Uniform buffer duplicates an existing binding number %d", binding);
|
||||
bindingsOk = false;
|
||||
}
|
||||
break;
|
||||
case QRhiShaderResourceBinding::SampledTexture:
|
||||
if (!bindingSeen[binding]) {
|
||||
bindingSeen[binding] = true;
|
||||
} else {
|
||||
qWarning("Combined image sampler duplicates an existing binding number %d", binding);
|
||||
bindingsOk = false;
|
||||
}
|
||||
break;
|
||||
case QRhiShaderResourceBinding::ImageLoad:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::ImageStore:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||
if (!bindingSeen[binding]) {
|
||||
bindingSeen[binding] = true;
|
||||
} else {
|
||||
qWarning("Image duplicates an existing binding number %d", binding);
|
||||
bindingsOk = false;
|
||||
}
|
||||
break;
|
||||
case QRhiShaderResourceBinding::BufferLoad:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::BufferStore:
|
||||
Q_FALLTHROUGH();
|
||||
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||
if (!bindingSeen[binding]) {
|
||||
bindingSeen[binding] = true;
|
||||
} else {
|
||||
qWarning("Buffer duplicates an existing binding number %d", binding);
|
||||
bindingsOk = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qWarning("Unknown binding type %d", int(it->data()->type));
|
||||
bindingsOk = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bindingsOk) {
|
||||
qWarning() << *srb;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(srb);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ public:
|
|||
}
|
||||
|
||||
bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
|
||||
bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
|
||||
|
||||
QRhi *q;
|
||||
|
||||
|
|
|
|||
|
|
@ -3421,6 +3421,10 @@ bool QD3D11ShaderResourceBindings::create()
|
|||
if (!sortedBindings.isEmpty())
|
||||
destroy();
|
||||
|
||||
QRHI_RES_RHI(QRhiD3D11);
|
||||
if (!rhiD->sanityCheckShaderResourceBindings(this))
|
||||
return false;
|
||||
|
||||
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
||||
|
|
|
|||
|
|
@ -4192,6 +4192,10 @@ void QGles2ShaderResourceBindings::destroy()
|
|||
|
||||
bool QGles2ShaderResourceBindings::create()
|
||||
{
|
||||
QRHI_RES_RHI(QRhiGles2);
|
||||
if (!rhiD->sanityCheckShaderResourceBindings(this))
|
||||
return false;
|
||||
|
||||
generation += 1;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2993,6 +2993,10 @@ bool QMetalShaderResourceBindings::create()
|
|||
if (!sortedBindings.isEmpty())
|
||||
destroy();
|
||||
|
||||
QRHI_RES_RHI(QRhiMetal);
|
||||
if (!rhiD->sanityCheckShaderResourceBindings(this))
|
||||
return false;
|
||||
|
||||
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
|
||||
std::sort(sortedBindings.begin(), sortedBindings.end(),
|
||||
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
|
||||
|
|
|
|||
|
|
@ -6155,6 +6155,10 @@ bool QVkShaderResourceBindings::create()
|
|||
if (layout)
|
||||
destroy();
|
||||
|
||||
QRHI_RES_RHI(QRhiVulkan);
|
||||
if (!rhiD->sanityCheckShaderResourceBindings(this))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
||||
descSets[i] = VK_NULL_HANDLE;
|
||||
|
||||
|
|
@ -6187,7 +6191,6 @@ bool QVkShaderResourceBindings::create()
|
|||
layoutInfo.bindingCount = uint32_t(vkbindings.count());
|
||||
layoutInfo.pBindings = vkbindings.constData();
|
||||
|
||||
QRHI_RES_RHI(QRhiVulkan);
|
||||
VkResult err = rhiD->df->vkCreateDescriptorSetLayout(rhiD->dev, &layoutInfo, nullptr, &layout);
|
||||
if (err != VK_SUCCESS) {
|
||||
qWarning("Failed to create descriptor set layout: %d", err);
|
||||
|
|
|
|||
Loading…
Reference in New Issue