eglfs: kms: Fix hw cursor with multiple screens

We used to have the assumption that moving the cursor to an out of
range position is valid and will result in a hidden cursor.

This is apparently not the case. For example, on an RPi4 with Mesa
V3D we get lots of funny artifacts after doing drmModeMoveCursor()
to invalid positions.

To remedy this, start hiding the cursor correctly when the position
is clearly out of the screen's bounds.

Task-number: QTBUG-79924
Change-Id: I3ef7ad0ce928546399443f21452f0b6deadf8036
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2019-11-11 12:24:31 +01:00
parent 6e42ed217c
commit 813e4460de
6 changed files with 51 additions and 10 deletions

View File

@ -214,7 +214,8 @@ void QEglFSKmsGbmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
if (kmsScreen->isCursorOutOfRange())
continue;
int status = drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, handle,
m_cursorSize.width(), m_cursorSize.height());
if (status != 0)
@ -232,17 +233,36 @@ void QEglFSKmsGbmCursor::setPos(const QPoint &pos)
{
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
QPoint origin = kmsScreen->geometry().topLeft();
QPoint localPos = pos - origin;
QPoint adjustedPos = localPos - m_cursorImage.hotspot();
const QRect screenGeom = kmsScreen->geometry();
const QPoint origin = screenGeom.topLeft();
const QPoint localPos = pos - origin;
const QPoint adjustedLocalPos = localPos - m_cursorImage.hotspot();
int ret = drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, adjustedPos.x(), adjustedPos.y());
if (ret == 0)
m_pos = pos;
else
qWarning("Failed to move cursor on screen %s: %d", kmsScreen->name().toLatin1().constData(), ret);
if (localPos.x() < 0 || localPos.y() < 0
|| localPos.x() >= screenGeom.width() || localPos.y() >= screenGeom.height())
{
if (!kmsScreen->isCursorOutOfRange()) {
kmsScreen->setCursorOutOfRange(true);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
}
} else {
int ret;
if (kmsScreen->isCursorOutOfRange()) {
kmsScreen->setCursorOutOfRange(false);
uint32_t handle = gbm_bo_get_handle(m_bo).u32;
ret = drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id,
handle, m_cursorSize.width(), m_cursorSize.height());
} else {
ret = drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id,
adjustedLocalPos.x(), adjustedLocalPos.y());
}
if (ret == 0)
m_pos = pos;
else
qWarning("Failed to move cursor on screen %s: %d", kmsScreen->name().toLatin1().constData(), ret);
kmsScreen->handleCursorMove(pos);
kmsScreen->handleCursorMove(pos);
}
}
}

View File

@ -85,6 +85,8 @@ public:
void updateMouseStatus();
void reevaluateVisibilityForScreens() { setPos(pos()); }
private:
void initCursorAtlas();

View File

@ -155,4 +155,14 @@ void QEglFSKmsGbmDevice::registerScreenCloning(QPlatformScreen *screen,
gbmScreen->initCloning(screenThisScreenClones, screensCloningThisScreen);
}
void QEglFSKmsGbmDevice::registerScreen(QPlatformScreen *screen,
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings)
{
QEglFSKmsDevice::registerScreen(screen, isPrimary, virtualPos, virtualSiblings);
if (screenConfig()->hwCursor() && m_globalCursor)
m_globalCursor->reevaluateVisibilityForScreens();
}
QT_END_NAMESPACE

View File

@ -70,6 +70,10 @@ public:
void registerScreenCloning(QPlatformScreen *screen,
QPlatformScreen *screenThisScreenClones,
const QVector<QPlatformScreen *> &screensCloningThisScreen) override;
void registerScreen(QPlatformScreen *screen,
bool isPrimary,
const QPoint &virtualPos,
const QList<QPlatformScreen *> &virtualSiblings) override;
private:
Q_DISABLE_COPY(QEglFSKmsGbmDevice)

View File

@ -72,6 +72,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output, b
: QEglFSScreen(static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->display())
, m_device(device)
, m_output(output)
, m_cursorOutOfRange(false)
, m_powerState(PowerStateOn)
, m_interruptHandler(new QEglFSKmsInterruptHandler(this))
, m_headless(headless)

View File

@ -99,12 +99,16 @@ public:
QPlatformScreen::PowerState powerState() const override;
void setPowerState(QPlatformScreen::PowerState state) override;
bool isCursorOutOfRange() const { return m_cursorOutOfRange; }
void setCursorOutOfRange(bool b) { m_cursorOutOfRange = b; }
protected:
QKmsDevice *m_device;
QKmsOutput m_output;
QEdidParser m_edid;
QPoint m_pos;
bool m_cursorOutOfRange;
QList<QPlatformScreen *> m_siblings;