From 037e4f9a5a2309a97ce50e7134ee43bcecd74b1f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 3 Feb 2025 14:38:39 +0100 Subject: [PATCH] rhi: Add autotest for continuous readback Exercises both the fix for the Vulkan/D3D12 readback problems, and the D3D12 finish() fix. Task-number: QTBUG-133454 Task-number: QTBUG-133405 Change-Id: Ida34c42a9be0a7913d4e8de9f0676d126fea2523 Reviewed-by: Andy Nichols --- tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index d10120b27a2..bb713a3e23b 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -120,6 +120,8 @@ private slots: void renderToTextureArrayMultiView(); void renderToWindowSimple_data(); void renderToWindowSimple(); + void continuousReadbackFromWindow_data(); + void continuousReadbackFromWindow(); void finishWithinSwapchainFrame_data(); void finishWithinSwapchainFrame(); void resourceUpdateBatchBufferTextureWithSwapchainFrames_data(); @@ -4088,6 +4090,84 @@ void tst_QRhi::renderToWindowSimple() QVERIFY(redCount < blueCount); } +void tst_QRhi::continuousReadbackFromWindow_data() +{ + rhiTestData(); +} + +void tst_QRhi::continuousReadbackFromWindow() +{ + if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive)) + QSKIP("Offscreen: This fails."); + + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + QScopedPointer rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QScopedPointer window(new QWindow); + setWindowType(window.data(), impl); + + window->setGeometry(0, 0, 640, 480); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QScopedPointer swapChain(rhi->newSwapChain()); + swapChain->setWindow(window.data()); + swapChain->setFlags(QRhiSwapChain::UsedAsTransferSource); + QScopedPointer rpDesc(swapChain->newCompatibleRenderPassDescriptor()); + swapChain->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(swapChain->createOrResize()); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + QScopedPointer vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices))); + QVERIFY(vbuf->create()); + updates->uploadStaticBuffer(vbuf.data(), triangleVertices); + + QScopedPointer srb(rhi->newShaderResourceBindings()); + QVERIFY(srb->create()); + + QScopedPointer pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data())); + QVERIFY(pipeline); + + const int asyncReadbackFrames = rhi->resourceLimit(QRhi::MaxAsyncReadbackFrames); + const int FRAME_COUNT = asyncReadbackFrames * 10; + QVector readResults(FRAME_COUNT); + int readbackCompletedCount = 0; + + for (int frameNo = 0; frameNo < FRAME_COUNT; ++frameNo) { + QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess); + QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer(); + QRhiRenderTarget *rt = swapChain->currentFrameRenderTarget(); + const QSize outputSize = swapChain->currentPixelSize(); + QRhiViewport viewport(0, 0, float(outputSize.width()), float(outputSize.height())); + + cb->beginPass(rt, Qt::blue, { 1.0f, 0 }, updates); + updates = nullptr; + cb->setGraphicsPipeline(pipeline.data()); + cb->setViewport(viewport); + QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0); + cb->setVertexInput(0, 1, &vbindings); + cb->draw(3); + + readResults[frameNo].completed = [&readbackCompletedCount] { + readbackCompletedCount += 1; + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({}, &readResults[frameNo]); // read back the current backbuffer + cb->endPass(readbackBatch); + + rhi->endFrame(swapChain.data()); + } + + QVERIFY(readbackCompletedCount >= FRAME_COUNT - asyncReadbackFrames); + rhi->finish(); + QCOMPARE(readbackCompletedCount, FRAME_COUNT); +} + void tst_QRhi::finishWithinSwapchainFrame_data() { rhiTestData();