aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgrhisupport.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2020-05-13 11:42:35 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2020-05-18 18:49:06 +0200
commit1e30ec77aaedcc29ba7ac1c3ec3937ee0b8287e9 (patch)
treef73fe032c760f70c239c4cc53b58e18fb1b7f153 /src/quick/scenegraph/qsgrhisupport.cpp
parent6ef31dfb484321ec6f5a3ffe27fef98e7c1cd3b0 (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.cpp79
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(&params);
+
+ // 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;