From eadfcb3d4f12cc4ee29f8672dd6869a99b6f9dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Fri, 14 Oct 2016 15:53:02 +0200 Subject: [PATCH] [effects] Make screenshot effect work with multiple output rendering Summary: Adjusts the screenshot effect to mutliple output rendering. In that case the blit from framebuffer can only get one output. Thus the effect needs to blit every output and combine the rendering result. Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D3059 --- effects/screenshot/screenshot.cpp | 90 +++++++++++++++++++++++-------- effects/screenshot/screenshot.h | 8 ++- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp index 9de6201fe1..d50e21a998 100644 --- a/effects/screenshot/screenshot.cpp +++ b/effects/screenshot/screenshot.cpp @@ -68,10 +68,16 @@ static QImage xPictureToImage(xcb_render_picture_t srcPic, const QRect &geometry QImage img((*xImage)->data, (*xImage)->width, (*xImage)->height, (*xImage)->stride, QImage::Format_ARGB32_Premultiplied); // TODO: byte order might need swapping xcb_free_pixmap(c, xpix); - return img; + return img.copy(); } #endif +void ScreenShotEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data) +{ + m_cachedOutputGeometry = data.outputGeometry(); + effects->paintScreen(mask, region, data); +} + void ScreenShotEffect::postPaintScreen() { effects->postPaintScreen(); @@ -180,11 +186,62 @@ void ScreenShotEffect::postPaintScreen() } if (!m_scheduledGeometry.isNull()) { - m_replyConnection.send(m_replyMessage.createReply(blitScreenshot(m_scheduledGeometry))); - m_scheduledGeometry = QRect(); + if (!m_cachedOutputGeometry.isNull()) { + // special handling for per-output geometry rendering + const QRect intersection = m_scheduledGeometry.intersected(m_cachedOutputGeometry); + if (intersection.isEmpty()) { + // doesn't intersect, not going onto this screenshot + return; + } + const QImage img = blitScreenshot(intersection); + if (img.size() == m_scheduledGeometry.size()) { + // we are done + sendReplyImage(img); + return; + } + if (m_multipleOutputsImage.isNull()) { + m_multipleOutputsImage = QImage(m_scheduledGeometry.size(), QImage::Format_ARGB32); + m_multipleOutputsImage.fill(Qt::transparent); + } + QPainter p; + p.begin(&m_multipleOutputsImage); + p.drawImage(intersection.topLeft() - m_scheduledGeometry.topLeft(), img); + p.end(); + m_multipleOutputsRendered = m_multipleOutputsRendered.united(intersection); + if (m_multipleOutputsRendered.boundingRect() == m_scheduledGeometry) { + sendReplyImage(m_multipleOutputsImage); + } + + } else { + const QImage img = blitScreenshot(m_scheduledGeometry); + sendReplyImage(img); + } } } +void ScreenShotEffect::sendReplyImage(const QImage &img) +{ + m_replyConnection.send(m_replyMessage.createReply(saveTempImage(img))); + m_scheduledGeometry = QRect(); + m_multipleOutputsImage = QImage(); + m_multipleOutputsRendered = QRegion(); +} + +QString ScreenShotEffect::saveTempImage(const QImage &img) +{ + if (img.isNull()) { + return QString(); + } + QTemporaryFile temp(QDir::tempPath() + QDir::separator() + QLatin1String("kwin_screenshot_XXXXXX.png")); + temp.setAutoRemove(false); + if (!temp.open()) { + return QString(); + } + img.save(&temp); + temp.close(); + return temp.fileName(); +} + void ScreenShotEffect::screenshotWindowUnderCursor(int mask) { m_type = (ScreenShotType)mask; @@ -274,14 +331,14 @@ QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height) return QString(); } -QString ScreenShotEffect::blitScreenshot(const QRect &geometry) +QImage ScreenShotEffect::blitScreenshot(const QRect &geometry) { QImage img; if (effects->isOpenGLCompositing()) { if (!GLRenderTarget::blitSupported()) { qCDebug(KWINEFFECTS) << "Framebuffer Blit not supported"; - return QString(); + return img; } GLTexture tex(GL_RGBA8, geometry.width(), geometry.height()); GLRenderTarget target(tex); @@ -299,27 +356,16 @@ QString ScreenShotEffect::blitScreenshot(const QRect &geometry) } #ifdef KWIN_HAVE_XRENDER_COMPOSITING - xcb_image_t *xImage = NULL; -#endif if (effects->compositingType() == XRenderCompositing) { -#ifdef KWIN_HAVE_XRENDER_COMPOSITING + xcb_image_t *xImage = NULL; img = xPictureToImage(effects->xrenderBufferPicture(), geometry, &xImage); -#endif - } - - QTemporaryFile temp(QDir::tempPath() + QDir::separator() + QLatin1String("kwin_screenshot_XXXXXX.png")); - temp.setAutoRemove(false); - if (!temp.open()) { - return QString(); - } - img.save(&temp); -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - if (xImage) { - xcb_image_destroy(xImage); + if (xImage) { + xcb_image_destroy(xImage); + } } #endif - temp.close(); - return temp.fileName(); + + return img; } void ScreenShotEffect::grabPointerImage(QImage& snapshot, int offsetx, int offsety) diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h index 8caae54c05..8e4fa57a6c 100644 --- a/effects/screenshot/screenshot.h +++ b/effects/screenshot/screenshot.h @@ -42,6 +42,7 @@ public: }; ScreenShotEffect(); virtual ~ScreenShotEffect(); + void paintScreen(int mask, QRegion region, ScreenPaintData &data) override; virtual void postPaintScreen(); virtual bool isActive() const; @@ -86,12 +87,17 @@ private Q_SLOTS: private: void grabPointerImage(QImage& snapshot, int offsetx, int offsety); - QString blitScreenshot(const QRect &geometry); + QImage blitScreenshot(const QRect &geometry); + QString saveTempImage(const QImage &img); + void sendReplyImage(const QImage &img); EffectWindow *m_scheduledScreenshot; ScreenShotType m_type; QRect m_scheduledGeometry; QDBusConnection m_replyConnection; QDBusMessage m_replyMessage; + QRect m_cachedOutputGeometry; + QImage m_multipleOutputsImage; + QRegion m_multipleOutputsRendered; }; } // namespace