From 4a0128cac1c5e92a7e0958ccf043ea0333f824fc Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 26 Oct 2020 09:39:55 +0200 Subject: [PATCH] Clip software cursors If you play some video and the software cursor doesn't hover it, then the shadow cast by the cursor will be getting darker and darker with every frame. The main reason for that is that kwin paints the software cursor even if the rect behind it hasn't been damaged or repainted. --- platform.cpp | 1 + plugins/scenes/opengl/scene_opengl.cpp | 21 +++++++++++++++------ plugins/scenes/opengl/scene_opengl.h | 2 +- plugins/scenes/qpainter/scene_qpainter.cpp | 14 ++++++++------ plugins/scenes/qpainter/scene_qpainter.h | 2 +- plugins/scenes/xrender/scene_xrender.cpp | 4 ++-- plugins/scenes/xrender/scene_xrender.h | 2 +- scene.h | 2 +- 8 files changed, 30 insertions(+), 18 deletions(-) diff --git a/platform.cpp b/platform.cpp index 08e47609df..0cb89ef5b5 100644 --- a/platform.cpp +++ b/platform.cpp @@ -197,6 +197,7 @@ void Platform::setSoftWareCursor(bool set) disconnect(Cursors::self(), &Cursors::positionChanged, this, &Platform::triggerCursorRepaint); disconnect(Cursors::self(), &Cursors::currentCursorChanged, this, &Platform::triggerCursorRepaint); } + triggerCursorRepaint(); } void Platform::triggerCursorRepaint() diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp index a5e46ce660..77ae267106 100644 --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -555,7 +555,7 @@ void SceneOpenGL::insertWait() * Render cursor texture in case hardware cursor is disabled. * Useful for screen recording apps or backends that can't do planes. */ -void SceneOpenGL2::paintCursor() +void SceneOpenGL2::paintCursor(const QRegion &rendered) { Cursor* cursor = Cursors::self()->currentCursor(); @@ -566,6 +566,18 @@ void SceneOpenGL2::paintCursor() return; } + // figure out which part of the cursor needs to be repainted + const QPoint cursorPos = cursor->pos() - cursor->hotspot(); + const qreal scale = cursor->image().devicePixelRatio(); + const QRect cursorRect(QPoint(0, 0), cursor->image().size() / scale); + QRegion region; + for (const QRect &rect : rendered) { + region |= rect.translated(-cursorPos).intersected(cursorRect); + } + if (region.isEmpty()) { + return; + } + // lazy init texture cursor only in case we need software rendering if (!m_cursorTexture) { auto updateCursorTexture = [this] { @@ -585,9 +597,6 @@ void SceneOpenGL2::paintCursor() } // get cursor position in projection coordinates - const qreal scale = cursor->image().devicePixelRatio(); - const QPoint cursorPos = cursor->pos() - cursor->hotspot(); - const QRect cursorRect(QPoint(0, 0), m_cursorTexture->size() / scale); QMatrix4x4 mvp = m_projectionMatrix; mvp.translate(cursorPos.x(), cursorPos.y()); @@ -599,7 +608,7 @@ void SceneOpenGL2::paintCursor() m_cursorTexture->bind(); ShaderBinder binder(ShaderTrait::MapTexture); binder.shader()->setUniform(GLShader::ModelViewProjectionMatrix, mvp); - m_cursorTexture->render(QRegion(cursorRect), cursorRect); + m_cursorTexture->render(region, cursorRect); m_cursorTexture->unbind(); glDisable(GL_BLEND); } @@ -645,7 +654,7 @@ qint64 SceneOpenGL::paint(const QRegion &damage, const QList &toplev updateProjectionMatrix(); paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo, scaling); // call generic implementation - paintCursor(); + paintCursor(valid); GLVertexBuffer::streamingBuffer()->endOfFrame(); diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h index 60dca99e82..8d02e420e8 100644 --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -123,7 +123,7 @@ protected: Scene::Window *createWindow(Toplevel *t) override; void finalDrawWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data) override; void updateProjectionMatrix() override; - void paintCursor() override; + void paintCursor(const QRegion ®ion) override; private: void performPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data); diff --git a/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp index e4bac24414..2750a594e7 100644 --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -110,7 +110,7 @@ qint64 SceneQPainter::paint(const QRegion &_damage, const QList &top QRegion updateRegion, validRegion; paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion); overallUpdate = overallUpdate.united(updateRegion); - paintCursor(); + paintCursor(updateRegion); m_painter->restore(); m_painter->end(); @@ -128,7 +128,7 @@ qint64 SceneQPainter::paint(const QRegion &_damage, const QList &top QRegion updateRegion, validRegion; paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); - paintCursor(); + paintCursor(updateRegion); m_backend->showOverlay(); m_painter->end(); @@ -149,7 +149,7 @@ void SceneQPainter::paintBackground(const QRegion ®ion) } } -void SceneQPainter::paintCursor() +void SceneQPainter::paintCursor(const QRegion &rendered) { if (!kwinApp()->platform()->usesSoftwareCursor()) { return; @@ -160,9 +160,11 @@ void SceneQPainter::paintCursor() if (img.isNull()) { return; } - const QPoint cursorPos = cursor->pos(); - const QPoint hotspot = cursor->hotspot(); - m_painter->drawImage(cursorPos - hotspot, img); + + m_painter->save(); + m_painter->setClipRegion(rendered.intersected(cursor->geometry())); + m_painter->drawImage(cursor->geometry(), img); + m_painter->restore(); } void SceneQPainter::paintEffectQuickView(EffectQuickView *w) diff --git a/plugins/scenes/qpainter/scene_qpainter.h b/plugins/scenes/qpainter/scene_qpainter.h index 8a727d096f..1e03571ca4 100644 --- a/plugins/scenes/qpainter/scene_qpainter.h +++ b/plugins/scenes/qpainter/scene_qpainter.h @@ -50,7 +50,7 @@ public: protected: void paintBackground(const QRegion ®ion) override; Scene::Window *createWindow(Toplevel *toplevel) override; - void paintCursor() override; + void paintCursor(const QRegion ®ion) override; void paintEffectQuickView(EffectQuickView *w) override; private: diff --git a/plugins/scenes/xrender/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp index 1e93ce7029..1243caa22a 100644 --- a/plugins/scenes/xrender/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -1326,9 +1326,9 @@ Scene *XRenderFactory::create(QObject *parent) const #endif -void KWin::SceneXrender::paintCursor() +void KWin::SceneXrender::paintCursor(const QRegion ®ion) { - + Q_UNUSED(region) } void KWin::SceneXrender::paintEffectQuickView(KWin::EffectQuickView *w) diff --git a/plugins/scenes/xrender/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h index 4a93d6fa63..22f7cea0b1 100644 --- a/plugins/scenes/xrender/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -166,7 +166,7 @@ protected: void paintBackground(const QRegion ®ion) override; void paintGenericScreen(int mask, const ScreenPaintData &data) override; void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override; - void paintCursor() override; + void paintCursor(const QRegion ®ion) override; void paintEffectQuickView(EffectQuickView *w) override; private: explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr); diff --git a/scene.h b/scene.h index fc25ae5cc9..f03fb2132e 100644 --- a/scene.h +++ b/scene.h @@ -208,7 +208,7 @@ protected: void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint, QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect(), const qreal screenScale = 1.0); // Render cursor texture in case hardware cursor is disabled/non-applicable - virtual void paintCursor() = 0; + virtual void paintCursor(const QRegion ®ion) = 0; friend class EffectsHandlerImpl; // called after all effects had their paintScreen() called void finalPaintScreen(int mask, const QRegion ®ion, ScreenPaintData& data);