From 27ea1b952799fa025bd1e496f7977e1929778a3e Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Wed, 22 Jul 2020 19:22:36 +0200 Subject: [PATCH] screencasting: Expose necessary information to implement efficient screencasting --- abstract_output.h | 3 ++ abstract_wayland_output.h | 3 +- .../scenes/opengl/abstract_egl_backend.cpp | 13 +++++- .../scenes/opengl/abstract_egl_backend.h | 3 ++ platformsupport/scenes/opengl/backend.cpp | 6 +++ platformsupport/scenes/opengl/backend.h | 4 ++ .../platforms/x11/standalone/x11_output.cpp | 5 +++ plugins/platforms/x11/standalone/x11_output.h | 2 + plugins/scenes/opengl/scene_opengl.cpp | 42 +++++++++++++++++++ plugins/scenes/opengl/scene_opengl.h | 3 ++ plugins/scenes/qpainter/scene_qpainter.cpp | 2 - scene.cpp | 2 + scene.h | 12 ++++++ 13 files changed, 96 insertions(+), 4 deletions(-) diff --git a/abstract_output.h b/abstract_output.h index e0b5498af9..7a483aec06 100644 --- a/abstract_output.h +++ b/abstract_output.h @@ -172,6 +172,9 @@ public: */ virtual bool setGammaRamp(const GammaRamp &gamma); + /** Returns the resolution of the output. */ + virtual QSize pixelSize() const = 0; + private: Q_DISABLE_COPY(AbstractOutput) }; diff --git a/abstract_wayland_output.h b/abstract_wayland_output.h index 31e101ee5a..cc2ed4c017 100644 --- a/abstract_wayland_output.h +++ b/abstract_wayland_output.h @@ -73,7 +73,7 @@ public: QSize modeSize() const; // TODO: The name is ambiguous. Rename this function. - QSize pixelSize() const; + QSize pixelSize() const override; qreal scale() const override; @@ -125,6 +125,7 @@ public: Q_SIGNALS: void modeChanged(); + void outputChange(const QRegion &damagedRegion); protected: void initInterfaces(const QString &model, const QString &manufacturer, diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp index e32309dff4..e3f16ee72d 100644 --- a/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -27,6 +27,7 @@ along with this program. If not, see . #include "platform.h" #include "scene.h" #include "wayland_server.h" +#include "abstract_wayland_output.h" #include #include #include @@ -316,6 +317,17 @@ void AbstractEglBackend::setSurface(const EGLSurface &surface) kwinApp()->platform()->setSceneEglSurface(surface); } +QSharedPointer AbstractEglBackend::textureForOutput(AbstractOutput *requestedOutput) const +{ + QSharedPointer texture(new GLTexture(GL_RGBA8, requestedOutput->pixelSize())); + GLRenderTarget renderTarget(*texture); + + const QRect geo = requestedOutput->geometry(); + QRect invGeo(geo.left(), geo.bottom(), geo.width(), -geo.height()); + renderTarget.blitFromFramebuffer(invGeo); + return texture; +} + AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend) : SceneOpenGLTexturePrivate() , q(texture) @@ -630,4 +642,3 @@ bool AbstractEglTexture::updateFromInternalImageObject(WindowPixmap *pixmap) } } - diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.h b/platformsupport/scenes/opengl/abstract_egl_backend.h index db5f427b7e..6aac89c3eb 100644 --- a/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -37,6 +37,7 @@ namespace KWin { class EglDmabuf; +class AbstractOutput; class KWIN_EXPORT AbstractEglBackend : public QObject, public OpenGLBackend { @@ -59,6 +60,8 @@ public: return m_config; } + QSharedPointer textureForOutput(AbstractOutput *output) const override; + protected: AbstractEglBackend(); void setEglDisplay(const EGLDisplay &display); diff --git a/platformsupport/scenes/opengl/backend.cpp b/platformsupport/scenes/opengl/backend.cpp index 45b6fbd30a..cba622bab5 100644 --- a/platformsupport/scenes/opengl/backend.cpp +++ b/platformsupport/scenes/opengl/backend.cpp @@ -116,4 +116,10 @@ void OpenGLBackend::copyPixels(const QRegion ®ion) } } +QSharedPointer OpenGLBackend::textureForOutput(AbstractOutput* output) const +{ + Q_UNUSED(output) + return {}; +} + } diff --git a/platformsupport/scenes/opengl/backend.h b/platformsupport/scenes/opengl/backend.h index c311d21b9a..7f2b651644 100644 --- a/platformsupport/scenes/opengl/backend.h +++ b/platformsupport/scenes/opengl/backend.h @@ -28,12 +28,14 @@ along with this program. If not, see . namespace KWin { +class AbstractOutput; class OpenGLBackend; class OverlayWindow; class SceneOpenGL; class SceneOpenGLTexture; class SceneOpenGLTexturePrivate; class WindowPixmap; +class GLTexture; /** * @brief The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap. @@ -197,6 +199,8 @@ public: */ void copyPixels(const QRegion ®ion); + virtual QSharedPointer textureForOutput(AbstractOutput *output) const; + protected: /** * @brief Backend specific flushing of frame to screen. diff --git a/plugins/platforms/x11/standalone/x11_output.cpp b/plugins/platforms/x11/standalone/x11_output.cpp index 41b35379e8..110239fe86 100644 --- a/plugins/platforms/x11/standalone/x11_output.cpp +++ b/plugins/platforms/x11/standalone/x11_output.cpp @@ -98,4 +98,9 @@ void X11Output::setPhysicalSize(const QSize &size) m_physicalSize = size; } +QSize X11Output::pixelSize() const +{ + return geometry().size(); +} + } diff --git a/plugins/platforms/x11/standalone/x11_output.h b/plugins/platforms/x11/standalone/x11_output.h index ea890e42d7..52f269ebda 100644 --- a/plugins/platforms/x11/standalone/x11_output.h +++ b/plugins/platforms/x11/standalone/x11_output.h @@ -57,6 +57,8 @@ public: QSize physicalSize() const override; void setPhysicalSize(const QSize &size); + QSize pixelSize() const override; + private: void setCrtc(xcb_randr_crtc_t crtc); void setGammaRampSize(int size); diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp index 6608e25196..950890830e 100644 --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -49,6 +49,8 @@ along with this program. If not, see . #include "decorations/decoratedclient.h" #include +#include "abstract_wayland_output.h" +#include "abstract_egl_backend.h" #include #include #include @@ -889,6 +891,11 @@ QVector SceneOpenGL::openGLPlatformInterfaceExtensions() const return m_backend->extensions().toVector(); } +QSharedPointer SceneOpenGL::textureForOutput(AbstractOutput* output) const +{ + return m_backend->textureForOutput(output); +} + //**************************************** // SceneOpenGL2 //**************************************** @@ -1531,6 +1538,41 @@ void OpenGLWindow::performPaint(int mask, const QRegion ®ion, const WindowPai endRenderWindow(); } +QSharedPointer OpenGLWindow::windowTexture() +{ + auto frame = windowPixmap(); + + if (frame->children().isEmpty()) { + return QSharedPointer(new GLTexture(*frame->texture())); + } else { + auto effectWindow = window()->effectWindow(); + QRect geo(pos(), window()->clientSize()); + QSharedPointer texture(new GLTexture(GL_RGBA8, geo.size())); + + QScopedPointer framebuffer(new KWin::GLRenderTarget(*texture)); + GLRenderTarget::pushRenderTarget(framebuffer.data()); + + auto renderVSG = GLRenderTarget::virtualScreenGeometry(); + GLVertexBuffer::setVirtualScreenGeometry(geo); + GLRenderTarget::setVirtualScreenGeometry(geo); + + QMatrix4x4 mvp; + mvp.ortho(geo); + + WindowPaintData data(effectWindow); + data.setProjectionMatrix(mvp); + QSizeF size(geo.size()); + data.setYScale(-1); + data.setXTranslation(bufferOffset().x()); + data.setYTranslation(geo.height() + bufferOffset().y()); + + performPaint(Scene::PAINT_WINDOW_TRANSFORMED | Scene::PAINT_WINDOW_LANCZOS, geo, data); + GLRenderTarget::popRenderTarget(); + GLVertexBuffer::setVirtualScreenGeometry(renderVSG); + GLRenderTarget::setVirtualScreenGeometry(renderVSG); + return texture; + } +} //**************************************** // OpenGLWindowPixmap diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h index eb0d1da22e..3919b5915b 100644 --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -80,6 +80,7 @@ public: } QVector openGLPlatformInterfaceExtensions() const override; + QSharedPointer textureForOutput(AbstractOutput *output) const override; static SceneOpenGL *createScene(QObject *parent); @@ -100,6 +101,7 @@ protected: bool init_ok; private: bool viewportLimitsMatched(const QSize &size) const; + private: bool m_debug; OpenGLBackend *m_backend; @@ -189,6 +191,7 @@ public: WindowPixmap *createWindowPixmap() override; void performPaint(int mask, const QRegion ®ion, const WindowPaintData &data) override; + QSharedPointer windowTexture() override; private: QMatrix4x4 transformation(int mask, const WindowPaintData &data) const; diff --git a/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp index 98dca03e34..43313eb1fc 100644 --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -149,8 +149,6 @@ qint64 SceneQPainter::paint(const QRegion &_damage, const QList &top // do cleanup clearStackingOrder(); - emit frameRendered(); - return renderTimer.nsecsElapsed(); } diff --git a/scene.cpp b/scene.cpp index 80dfef835b..6b9c8bec95 100644 --- a/scene.cpp +++ b/scene.cpp @@ -198,6 +198,8 @@ void Scene::finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& d paintGenericScreen(mask, data); else paintSimpleScreen(mask, region); + + Q_EMIT frameRendered(); } // The generic painting code that can handle even transformations. diff --git a/scene.h b/scene.h index dda98097af..2e8d80ad79 100644 --- a/scene.h +++ b/scene.h @@ -52,6 +52,8 @@ class EffectWindowImpl; class OverlayWindow; class Shadow; class WindowPixmap; +class GLTexture; +class AbstractOutput; // The base class for compositing backends. class KWIN_EXPORT Scene : public QObject @@ -195,6 +197,11 @@ public: */ virtual QVector openGLPlatformInterfaceExtensions() const; + virtual QSharedPointer textureForOutput(AbstractOutput *output) const { + Q_UNUSED(output); + return {}; + } + Q_SIGNALS: void frameRendered(); void resetCompositing(); @@ -347,6 +354,11 @@ public: void unreferencePreviousPixmap(); void discardQuads(); void preprocess(); + + virtual QSharedPointer windowTexture() { + return {}; + } + protected: WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion ®ion, qreal textureScale = 1.0) const; WindowQuadList makeContentsQuads() const;