diff options
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 9 | ||||
-rw-r--r-- | tests/auto/gui/rhi/qrhi/tst_qrhi.cpp | 159 |
2 files changed, 146 insertions, 22 deletions
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index b46b0b819c..e67b249f9c 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -2001,10 +2001,13 @@ QRhi::FrameOpResult QRhiVulkan::finish() if (inFrame) { // Allocate and begin recording on a new command buffer. - if (ofr.active) + if (ofr.active) { startPrimaryCommandBuffer(&ofr.cbWrapper.cb); - else - startPrimaryCommandBuffer(&swapChainD->frameRes[swapChainD->currentFrameSlot].cmdBuf); + } else { + QVkSwapChain::FrameResources &frame(swapChainD->frameRes[swapChainD->currentFrameSlot]); + startPrimaryCommandBuffer(&frame.cmdBuf); + swapChainD->cbWrapper.cb = frame.cmdBuf; + } } executeDeferredReleases(true); diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index f437a7f1f8..d3524a39b7 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -101,12 +101,16 @@ private slots: void renderToTextureTexturedQuadAndUniformBuffer(); void renderToWindowSimple_data(); void renderToWindowSimple(); + void finishWithinSwapchainFrame_data(); + void finishWithinSwapchainFrame(); void srbLayoutCompatibility_data(); void srbLayoutCompatibility(); void renderPassDescriptorCompatibility_data(); void renderPassDescriptorCompatibility(); private: + void setWindowType(QWindow *window, QRhi::Implementation impl); + struct { QRhiNullInitParams null; #ifdef TST_GL @@ -2081,26 +2085,8 @@ void tst_QRhi::renderToTextureTexturedQuadAndUniformBuffer() QCOMPARE(result1.pixel(28, 178), empty); } -void tst_QRhi::renderToWindowSimple_data() -{ - rhiTestData(); -} - -void tst_QRhi::renderToWindowSimple() +void tst_QRhi::setWindowType(QWindow *window, QRhi::Implementation impl) { - QFETCH(QRhi::Implementation, impl); - QFETCH(QRhiInitParams *, initParams); - -#ifdef Q_OS_WINRT - if (impl == QRhi::D3D11) - QSKIP("Skipping window-based QRhi rendering on WinRT as the platform and the D3D11 backend are not prepared for this yet"); -#endif - - QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); - if (!rhi) - QSKIP("QRhi could not be created, skipping testing rendering"); - - QScopedPointer<QWindow> window(new QWindow); switch (impl) { case QRhi::OpenGLES2: #if QT_CONFIG(opengl) @@ -2122,6 +2108,29 @@ void tst_QRhi::renderToWindowSimple() default: break; } +} + +void tst_QRhi::renderToWindowSimple_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToWindowSimple() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + +#ifdef Q_OS_WINRT + if (impl == QRhi::D3D11) + QSKIP("Skipping window-based QRhi rendering on WinRT as the platform and the D3D11 backend are not prepared for this yet"); +#endif + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QScopedPointer<QWindow> window(new QWindow); + setWindowType(window.data(), impl); window->setGeometry(0, 0, 640, 480); window->show(); @@ -2241,6 +2250,118 @@ void tst_QRhi::renderToWindowSimple() QVERIFY(redCount < blueCount); } +void tst_QRhi::finishWithinSwapchainFrame_data() +{ + rhiTestData(); +} + +void tst_QRhi::finishWithinSwapchainFrame() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + +#ifdef Q_OS_WINRT + if (impl == QRhi::D3D11) + QSKIP("Skipping window-based QRhi rendering on WinRT as the platform and the D3D11 backend are not prepared for this yet"); +#endif + + QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + + QScopedPointer<QWindow> window(new QWindow); + setWindowType(window.data(), impl); + + window->setGeometry(0, 0, 640, 480); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QScopedPointer<QRhiSwapChain> swapChain(rhi->newSwapChain()); + swapChain->setWindow(window.data()); + swapChain->setFlags(QRhiSwapChain::UsedAsTransferSource); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(swapChain->newCompatibleRenderPassDescriptor()); + swapChain->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(swapChain->buildOrResize()); + + QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings()); + QVERIFY(srb->build()); + + QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline()); + QShader vs = loadShader(":/data/simple.vert.qsb"); + QVERIFY(vs.isValid()); + QShader fs = loadShader(":/data/simple.frag.qsb"); + QVERIFY(fs.isValid()); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ { 2 * sizeof(float) } }); + inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } }); + pipeline->setVertexInputLayout(inputLayout); + pipeline->setShaderResourceBindings(srb.data()); + pipeline->setRenderPassDescriptor(rpDesc.data()); + QVERIFY(pipeline->build()); + + static const float vertices[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + 0.0f, 1.0f + }; + QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices))); + QVERIFY(vbuf->build()); + + // exercise begin/endExternal() just a little bit, hence ExternalContentsInPass + QVERIFY(rhi->beginFrame(swapChain.data(), QRhi::ExternalContentsInPass) == QRhi::FrameOpSuccess); + QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer(); + QRhiRenderTarget *rt = swapChain->currentFrameRenderTarget(); + const QSize outputSize = swapChain->currentPixelSize(); + + // repeat a sequence of upload, renderpass, readback, finish a number of + // times within the same frame + for (int i = 0; i < 5; ++i) { + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + updates->uploadStaticBuffer(vbuf.data(), vertices); + + cb->beginPass(rt, Qt::blue, { 1.0f, 0 }, updates); + + // just have some commands, do not bother with draw calls + cb->setGraphicsPipeline(pipeline.data()); + QRhiViewport viewport(0, 0, float(outputSize.width()), float(outputSize.height())); + cb->setViewport(viewport); + + // do a dummy begin/endExternal round: interesting for Vulkan because + // there this may start end then submit a secondary command buffer + cb->beginExternal(); + cb->endExternal(); + + cb->endPass(); + + QRhiReadbackResult readResult; + bool ok = false; + readResult.completed = [&readResult, &ok, impl] { + QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_ARGB32_Premultiplied); + if (readResult.format == QRhiTexture::RGBA8) + wrapperImage = wrapperImage.rgbSwapped(); + + if (impl != QRhi::Null) + ok = qBlue(wrapperImage.pixel(43, 89)) > 250; + else + ok = true; // the Null backend does not actually render + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({}, &readResult); // read back the current backbuffer + cb->resourceUpdate(readbackBatch); + + // force submit what we have so far, wait for the queue, and then start + // a new primary command buffer + rhi->finish(); + + QVERIFY(ok); + } + + rhi->endFrame(swapChain.data()); +} + void tst_QRhi::srbLayoutCompatibility_data() { rhiTestData(); |