summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2019-11-26 12:43:56 +0100
committerLaszlo Agocs <laszlo.agocs@qt.io>2019-11-27 19:07:36 +0100
commit64760504e79c3069d99b5e852688a2589ec22028 (patch)
tree05524e084cbd5f9b08108b072d87209409d74e47 /tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
parent48d2ffd39786b2decad76132158aeba172a3b8a8 (diff)
rhi: Allow testing QRhiRenderPassDescriptors for compatibility
For Metal and Vulkan this needs actual work because that's where the concept of renderpass descriptors is relevant. GL and D3D can just return true always. The big benefit of this is that Qt Quick can now compare renderpass descriptors via isCompatible() for its pipeline cache (similarly to how it is already using isLayoutCompatible() for srbs), and so renderpass descriptors for layers (Item.layer, ShaderEffect) will typically be compatible and so can pick up pipelines created by other layers from the cache. Also add autotests for shader resource binding and renderpass descriptor compatibility. Task-number: QTBUG-80318 Change-Id: I0008bc51c4ee13b0113d2c8caf799e1257f18a18 Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
Diffstat (limited to 'tests/auto/gui/rhi/qrhi/tst_qrhi.cpp')
-rw-r--r--tests/auto/gui/rhi/qrhi/tst_qrhi.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
index 17d77c2b90..302630ae15 100644
--- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
+++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
@@ -91,6 +91,10 @@ private slots:
void renderToTextureTexturedQuadAndUniformBuffer();
void renderToWindowSimple_data();
void renderToWindowSimple();
+ void srbLayoutCompatibility_data();
+ void srbLayoutCompatibility();
+ void renderPassDescriptorCompatibility_data();
+ void renderPassDescriptorCompatibility();
private:
struct {
@@ -1728,5 +1732,318 @@ void tst_QRhi::renderToWindowSimple()
QVERIFY(redCount < blueCount);
}
+void tst_QRhi::srbLayoutCompatibility_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::srbLayoutCompatibility()
+{
+ QFETCH(QRhi::Implementation, impl);
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing texture resource updates");
+
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512)));
+ QVERIFY(texture->build());
+ QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ QVERIFY(sampler->build());
+ QScopedPointer<QRhiSampler> otherSampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ QVERIFY(otherSampler->build());
+ QScopedPointer<QRhiBuffer> buf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 1024));
+ QVERIFY(buf->build());
+ QScopedPointer<QRhiBuffer> otherBuf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256));
+ QVERIFY(otherBuf->build());
+
+ // empty (compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ QVERIFY(srb2->build());
+
+ QVERIFY(srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // different count (not compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::sampledTexture(0, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(!srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(!srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // full match (compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ srb1->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // different visibility (not compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ srb1->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, buf.data()),
+ });
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(!srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(!srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // different binding points (not compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ srb1->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ });
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(1, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(!srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(!srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // different buffer region offset and size (compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ srb1->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data(), rhi->ubufAligned(1), 128),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(srb2->isLayoutCompatible(srb1.data()));
+ }
+
+ // different resources (compatible)
+ {
+ QScopedPointer<QRhiShaderResourceBindings> srb1(rhi->newShaderResourceBindings());
+ srb1->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, otherBuf.data()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), otherSampler.data())
+ });
+ QVERIFY(srb1->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb2(rhi->newShaderResourceBindings());
+ srb2->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buf.data()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture.data(), sampler.data())
+ });
+ QVERIFY(srb2->build());
+
+ QVERIFY(srb1->isLayoutCompatible(srb2.data()));
+ QVERIFY(srb2->isLayoutCompatible(srb1.data()));
+ }
+}
+
+void tst_QRhi::renderPassDescriptorCompatibility_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderPassDescriptorCompatibility()
+{
+ QFETCH(QRhi::Implementation, impl);
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing texture resource updates");
+
+ // Note that checking compatibility is only relevant with backends where
+ // there is a concept of renderpass descriptions (Vulkan, and partially
+ // Metal). It is perfectly fine for isCompatible() to always return true
+ // when that is not the case (D3D11, OpenGL). Hence the 'if (Vulkan or
+ // Metal)' for all the negative tests. Also note "partial" for Metal:
+ // resolve textures for examples have no effect on compatibility with Metal.
+
+ // tex and tex2 have the same format
+ QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget));
+ QVERIFY(tex->build());
+ QScopedPointer<QRhiTexture> tex2(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget));
+ QVERIFY(tex2->build());
+
+ QScopedPointer<QRhiRenderBuffer> ds(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512)));
+ QVERIFY(ds->build());
+
+ // two texture rendertargets with tex and tex2 as color0 (compatible)
+ {
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget({ tex2.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
+ }
+
+ // two texture rendertargets with tex and tex2 as color0, and a depth-stencil attachment as well (compatible)
+ {
+ QRhiTextureRenderTargetDescription desc({ tex.data() }, ds.data());
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget(desc));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
+ }
+
+ // now one of them does not have the ds attachment (not compatible)
+ {
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ { tex.data() }, ds.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget({ tex.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ if (impl == QRhi::Vulkan || impl == QRhi::Metal) {
+ QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
+ }
+ }
+
+ if (rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
+ // resolve attachments (compatible)
+ {
+ QScopedPointer<QRhiRenderBuffer> msaaRenderBuffer(rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4));
+ QVERIFY(msaaRenderBuffer->build());
+ QScopedPointer<QRhiRenderBuffer> msaaRenderBuffer2(rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4));
+ QVERIFY(msaaRenderBuffer2->build());
+
+ QRhiColorAttachment colorAtt(msaaRenderBuffer.data()); // color0, multisample
+ colorAtt.setResolveTexture(tex.data()); // resolved into a non-msaa texture
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ colorAtt }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QRhiColorAttachment colorAtt2(msaaRenderBuffer2.data()); // color0, multisample
+ colorAtt2.setResolveTexture(tex2.data()); // resolved into a non-msaa texture
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget({ colorAtt2 }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ QVERIFY(rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(rpDesc2->isCompatible(rpDesc.data()));
+ }
+
+ // missing resolve for one of them (not compatible)
+ {
+ QScopedPointer<QRhiRenderBuffer> msaaRenderBuffer(rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4));
+ QVERIFY(msaaRenderBuffer->build());
+ QScopedPointer<QRhiRenderBuffer> msaaRenderBuffer2(rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4));
+ QVERIFY(msaaRenderBuffer2->build());
+
+ QRhiColorAttachment colorAtt(msaaRenderBuffer.data()); // color0, multisample
+ colorAtt.setResolveTexture(tex.data()); // resolved into a non-msaa texture
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ colorAtt }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QRhiColorAttachment colorAtt2(msaaRenderBuffer2.data()); // color0, multisample
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget({ colorAtt2 }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ if (impl == QRhi::Vulkan) { // no Metal here
+ QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
+ }
+ }
+ } else {
+ qDebug("Skipping multisample renderbuffer dependent tests");
+ }
+
+ if (rhi->isTextureFormatSupported(QRhiTexture::RGBA32F)) {
+ QScopedPointer<QRhiTexture> tex3(rhi->newTexture(QRhiTexture::RGBA32F, QSize(512, 512), 1, QRhiTexture::RenderTarget));
+ QVERIFY(tex3->build());
+
+ // different texture formats (not compatible)
+ {
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt2(rhi->newTextureRenderTarget({ tex3.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc2(rt2->newCompatibleRenderPassDescriptor());
+ rt2->setRenderPassDescriptor(rpDesc2.data());
+ QVERIFY(rt2->build());
+
+ if (impl == QRhi::Vulkan || impl == QRhi::Metal) {
+ QVERIFY(!rpDesc->isCompatible(rpDesc2.data()));
+ QVERIFY(!rpDesc2->isCompatible(rpDesc.data()));
+ }
+ }
+ } else {
+ qDebug("Skipping texture format dependent tests");
+ }
+}
+
#include <tst_qrhi.moc>
QTEST_MAIN(tst_QRhi)