Commit ff4a0d97 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

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.

(cherry picked from commit 4a0128ca)
parent 838d7e7a
......@@ -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()
......
......@@ -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<Toplevel *> &toplev
updateProjectionMatrix();
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo, scaling); // call generic implementation
paintCursor();
paintCursor(valid);
GLVertexBuffer::streamingBuffer()->endOfFrame();
......
......@@ -122,7 +122,7 @@ protected:
Scene::Window *createWindow(Toplevel *t) override;
void finalDrawWindow(EffectWindowImpl* w, int mask, const QRegion &region, WindowPaintData& data) override;
void updateProjectionMatrix() override;
void paintCursor() override;
void paintCursor(const QRegion &region) override;
private:
void performPaintWindow(EffectWindowImpl* w, int mask, const QRegion &region, WindowPaintData& data);
......
......@@ -110,7 +110,7 @@ qint64 SceneQPainter::paint(const QRegion &_damage, const QList<Toplevel *> &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<Toplevel *> &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 &region)
}
}
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)
......
......@@ -50,7 +50,7 @@ public:
protected:
void paintBackground(const QRegion &region) override;
Scene::Window *createWindow(Toplevel *toplevel) override;
void paintCursor() override;
void paintCursor(const QRegion &region) override;
void paintEffectQuickView(EffectQuickView *w) override;
private:
......
......@@ -1326,9 +1326,9 @@ Scene *XRenderFactory::create(QObject *parent) const
#endif
void KWin::SceneXrender::paintCursor()
void KWin::SceneXrender::paintCursor(const QRegion &region)
{
Q_UNUSED(region)
}
void KWin::SceneXrender::paintEffectQuickView(KWin::EffectQuickView *w)
......
......@@ -166,7 +166,7 @@ protected:
void paintBackground(const QRegion &region) override;
void paintGenericScreen(int mask, const ScreenPaintData &data) override;
void paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data) override;
void paintCursor() override;
void paintCursor(const QRegion &region) override;
void paintEffectQuickView(EffectQuickView *w) override;
private:
explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr);
......
......@@ -207,7 +207,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 &region) = 0;
friend class EffectsHandlerImpl;
// called after all effects had their paintScreen() called
void finalPaintScreen(int mask, const QRegion &region, ScreenPaintData& data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment