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
Laszlo Agocs 2020-09-01 15:16:24 +02:00
parent 95daeb2407
commit f6802a5aac
6 changed files with 91 additions and 2 deletions

View File

@ -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
*/

View File

@ -210,6 +210,7 @@ public:
}
bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
QRhi *q;

View File

@ -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)

View File

@ -4192,6 +4192,10 @@ void QGles2ShaderResourceBindings::destroy()
bool QGles2ShaderResourceBindings::create()
{
QRHI_RES_RHI(QRhiGles2);
if (!rhiD->sanityCheckShaderResourceBindings(this))
return false;
generation += 1;
return true;
}

View File

@ -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)

View File

@ -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);