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.
icc-effect-5.26.4
Vlad Zahorodnii 2020-10-26 09:39:55 +02:00
parent 4b12afced9
commit 4a0128cac1
8 changed files with 30 additions and 18 deletions

View File

@ -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()

View File

@ -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();

View File

@ -123,7 +123,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);

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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);

View File

@ -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 &region) = 0;
friend class EffectsHandlerImpl;
// called after all effects had their paintScreen() called
void finalPaintScreen(int mask, const QRegion &region, ScreenPaintData& data);