diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2020-05-13 11:42:35 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2020-05-18 18:49:06 +0200 |
commit | 1e30ec77aaedcc29ba7ac1c3ec3937ee0b8287e9 (patch) | |
tree | f73fe032c760f70c239c4cc53b58e18fb1b7f153 /src/quick/scenegraph/qsgrhisupport.cpp | |
parent | 6ef31dfb484321ec6f5a3ffe27fef98e7c1cd3b0 (diff) |
rhi: Add support for grabbing non-exposed windows
tst_qquickwindow::grab is now expected to pass in all combinations
(both direct GL and RHI with any backend).
Task-number: QTBUG-78608
Change-Id: I8c1f2ff3d50144c7dd4498160818d0860b67db15
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src/quick/scenegraph/qsgrhisupport.cpp')
-rw-r--r-- | src/quick/scenegraph/qsgrhisupport.cpp | 79 |
1 files changed, 76 insertions, 3 deletions
diff --git a/src/quick/scenegraph/qsgrhisupport.cpp b/src/quick/scenegraph/qsgrhisupport.cpp index b86667a972..df1a0e072c 100644 --- a/src/quick/scenegraph/qsgrhisupport.cpp +++ b/src/quick/scenegraph/qsgrhisupport.cpp @@ -52,6 +52,7 @@ #endif #include <QOperatingSystemVersion> +#include <QOffscreenSurface> QT_BEGIN_NAMESPACE @@ -630,16 +631,16 @@ QRhi *QSGRhiSupport::createRhi(QQuickWindow *window, QOffscreenSurface *offscree return rhi; } -QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapchain) +QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiCommandBuffer *cb, QRhiTexture *src) { Q_ASSERT(rhi->isRecordingFrame()); QRhiReadbackResult result; - QRhiReadbackDescription readbackDesc; // read from swapchain backbuffer + QRhiReadbackDescription readbackDesc(src); // null src == read from swapchain backbuffer QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch(); resourceUpdates->readBackTexture(readbackDesc, &result); - swapchain->currentFrameCommandBuffer()->resourceUpdate(resourceUpdates); + cb->resourceUpdate(resourceUpdates); rhi->finish(); // make sure the readback has finished, stall the pipeline if needed // May be RGBA or BGRA. Plus premultiplied alpha. @@ -664,6 +665,78 @@ QImage QSGRhiSupport::grabAndBlockInCurrentFrame(QRhi *rhi, QRhiSwapChain *swapc return img.copy(); } +QImage QSGRhiSupport::grabOffscreen(QQuickWindow *window) +{ + // Set up and then tear down the entire rendering infrastructure. This + // function is called on the gui/main thread - but that's alright because + // there is no onscreen rendering initialized at this point (so no render + // thread for instance). + + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + // It is expected that window is not using QQuickRenderControl, i.e. it is + // a normal QQuickWindow that just happens to be not exposed. + Q_ASSERT(!wd->renderControl); + + QScopedPointer<QOffscreenSurface> offscreenSurface(maybeCreateOffscreenSurface(window)); + QScopedPointer<QRhi> rhi(createRhi(window, offscreenSurface.data())); + if (!rhi) { + qWarning("Failed to initialize QRhi for offscreen readback"); + return QImage(); + } + + const QSize pixelSize = window->size() * window->devicePixelRatio(); + QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, pixelSize, 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + if (!texture->build()) { + qWarning("Failed to build texture for offscreen readback"); + return QImage(); + } + QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() })); + QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.data()); + if (!rt->build()) { + qWarning("Failed to build render target for offscreen readback"); + return QImage(); + } + + wd->rhi = rhi.data(); + + QSGDefaultRenderContext::InitParams params; + params.rhi = rhi.data(); + params.sampleCount = 1; + params.initialSurfacePixelSize = pixelSize; + params.maybeSurface = window; + wd->context->initialize(¶ms); + + // There was no rendercontrol which means a custom render target + // should not be set either. Set our own, temporarily. + window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(rt.data())); + + QRhiCommandBuffer *cb = nullptr; + if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess) { + qWarning("Failed to start recording the frame for offscreen readback"); + return QImage(); + } + + wd->setCustomCommandBuffer(cb); + wd->polishItems(); + wd->syncSceneGraph(); + wd->renderSceneGraph(window->size()); + wd->setCustomCommandBuffer(nullptr); + + QImage image = grabAndBlockInCurrentFrame(rhi.data(), cb, texture.data()); + rhi->endOffscreenFrame(); + + image.setDevicePixelRatio(window->devicePixelRatio()); + wd->cleanupNodesOnShutdown(); + wd->context->invalidate(); + + window->setRenderTarget(QQuickRenderTarget()); + wd->rhi = nullptr; + + return image; +} + QSGRhiProfileConnection *QSGRhiProfileConnection::instance() { static QSGRhiProfileConnection inst; |