eglfs_kms: Virtual desktop

Now we can choose to use separate screens or virtual desktop.

With virtual desktop the geometry of all screens is taken
into account so that the input plugin do not clamp global
pointer coordinates to the first screen anymore, we also
create only one hardware cursor that can now freely move
on all the screens.

Virtual desktop is enabled by default, but the old default
behavior can be restored by setting separateScreens to true.

Change-Id: I78dbf9e8d3dd44f68d33350dc8fc3727bf8a26fe
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
This commit is contained in:
Pier Luigi Fiorini 2015-05-22 20:30:59 +02:00
parent f7047d52da
commit 11512d6a2c
7 changed files with 86 additions and 14 deletions

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -87,8 +88,11 @@ QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
QEglFSKmsCursor::~QEglFSKmsCursor() QEglFSKmsCursor::~QEglFSKmsCursor()
{ {
drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0); Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0); QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0);
}
gbm_bo_destroy(m_bo); gbm_bo_destroy(m_bo);
m_bo = Q_NULLPTR; m_bo = Q_NULLPTR;
@ -143,10 +147,15 @@ void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
gbm_bo_write(m_bo, cursorImage.constBits(), cursorImage.byteCount()); gbm_bo_write(m_bo, cursorImage.constBits(), cursorImage.byteCount());
uint32_t handle = gbm_bo_get_handle(m_bo).u32; uint32_t handle = gbm_bo_get_handle(m_bo).u32;
int status = drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, handle,
m_cursorSize.width(), m_cursorSize.height()); Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
if (status != 0) QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
qWarning("Could not set cursor: %d", status);
int status = drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, handle,
m_cursorSize.width(), m_cursorSize.height());
if (status != 0)
qWarning("Could not set cursor on screen %s: %d", kmsScreen->name().toLatin1().constData(), status);
}
} }
#endif // QT_NO_CURSOR #endif // QT_NO_CURSOR
@ -157,12 +166,17 @@ QPoint QEglFSKmsCursor::pos() const
void QEglFSKmsCursor::setPos(const QPoint &pos) void QEglFSKmsCursor::setPos(const QPoint &pos)
{ {
QPoint adjustedPos = pos - m_cursorImage.hotspot(); Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
int ret = drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, adjustedPos.x(), adjustedPos.y()); QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
if (ret == 0) { QPoint origin = kmsScreen->geometry().topLeft();
m_pos = pos; QPoint localPos = pos - origin;
} else { QPoint adjustedPos = localPos - m_cursorImage.hotspot();
qWarning("Failed to move cursor: %d", ret);
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);
} }
} }
@ -176,8 +190,11 @@ void QEglFSKmsCursor::initCursorAtlas()
QFile file(QString::fromUtf8(json)); QFile file(QString::fromUtf8(json));
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0); Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0); QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
drmModeSetCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(kmsScreen->device()->fd(), kmsScreen->output().crtc_id, 0, 0);
}
m_visible = false; m_visible = false;
return; return;
} }

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -308,6 +309,7 @@ QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QStrin
, m_gbm_device(Q_NULLPTR) , m_gbm_device(Q_NULLPTR)
, m_crtc_allocator(0) , m_crtc_allocator(0)
, m_connector_allocator(0) , m_connector_allocator(0)
, m_globalCursor(Q_NULLPTR)
{ {
} }
@ -347,6 +349,10 @@ void QEglFSKmsDevice::close()
qt_safe_close(m_dri_fd); qt_safe_close(m_dri_fd);
m_dri_fd = -1; m_dri_fd = -1;
} }
if (m_globalCursor)
m_globalCursor->deleteLater();
m_globalCursor = Q_NULLPTR;
} }
void QEglFSKmsDevice::createScreens() void QEglFSKmsDevice::createScreens()
@ -357,6 +363,8 @@ void QEglFSKmsDevice::createScreens()
return; return;
} }
QEglFSKmsScreen *primaryScreen = Q_NULLPTR;
QList<QPlatformScreen *> siblings;
QPoint pos(0, 0); QPoint pos(0, 0);
QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration()); QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
@ -369,12 +377,24 @@ void QEglFSKmsDevice::createScreens()
if (screen) { if (screen) {
integration->addScreen(screen); integration->addScreen(screen);
pos.rx() += screen->geometry().width(); pos.rx() += screen->geometry().width();
siblings << screen;
if (!primaryScreen)
primaryScreen = screen;
} }
drmModeFreeConnector(connector); drmModeFreeConnector(connector);
} }
drmModeFreeResources(resources); drmModeFreeResources(resources);
if (!m_integration->separateScreens()) {
Q_FOREACH (QPlatformScreen *screen, siblings)
static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings);
if (primaryScreen)
m_globalCursor = new QEglFSKmsCursor(primaryScreen);
}
} }
gbm_device *QEglFSKmsDevice::device() const gbm_device *QEglFSKmsDevice::device() const
@ -387,6 +407,11 @@ int QEglFSKmsDevice::fd() const
return m_dri_fd; return m_dri_fd;
} }
QPlatformCursor *QEglFSKmsDevice::globalCursor() const
{
return m_globalCursor;
}
void QEglFSKmsDevice::handleDrmEvent() void QEglFSKmsDevice::handleDrmEvent()
{ {
drmEventContext drmEvent = { drmEventContext drmEvent = {

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -34,6 +35,7 @@
#ifndef QEGLFSKMSDEVICE_H #ifndef QEGLFSKMSDEVICE_H
#define QEGLFSKMSDEVICE_H #define QEGLFSKMSDEVICE_H
#include "qeglfskmscursor.h"
#include "qeglfskmsintegration.h" #include "qeglfskmsintegration.h"
#include <xf86drm.h> #include <xf86drm.h>
@ -57,6 +59,8 @@ public:
gbm_device *device() const; gbm_device *device() const;
int fd() const; int fd() const;
QPlatformCursor *globalCursor() const;
void handleDrmEvent(); void handleDrmEvent();
private: private:
@ -70,6 +74,8 @@ private:
quint32 m_crtc_allocator; quint32 m_crtc_allocator;
quint32 m_connector_allocator; quint32 m_connector_allocator;
QEglFSKmsCursor *m_globalCursor;
int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector); int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
QEglFSKmsScreen *screenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos); QEglFSKmsScreen *screenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos);

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -60,6 +61,7 @@ QEglFSKmsIntegration::QEglFSKmsIntegration()
: m_device(Q_NULLPTR) : m_device(Q_NULLPTR)
, m_hwCursor(true) , m_hwCursor(true)
, m_pbuffers(false) , m_pbuffers(false)
, m_separateScreens(false)
{} {}
void QEglFSKmsIntegration::platformInit() void QEglFSKmsIntegration::platformInit()
@ -203,6 +205,11 @@ bool QEglFSKmsIntegration::hwCursor() const
return m_hwCursor; return m_hwCursor;
} }
bool QEglFSKmsIntegration::separateScreens() const
{
return m_separateScreens;
}
QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const
{ {
return m_outputSettings; return m_outputSettings;
@ -235,6 +242,7 @@ void QEglFSKmsIntegration::loadConfig()
m_hwCursor = object.value(QStringLiteral("hwcursor")).toBool(m_hwCursor); m_hwCursor = object.value(QStringLiteral("hwcursor")).toBool(m_hwCursor);
m_pbuffers = object.value(QStringLiteral("pbuffers")).toBool(m_pbuffers); m_pbuffers = object.value(QStringLiteral("pbuffers")).toBool(m_pbuffers);
m_devicePath = object.value(QStringLiteral("device")).toString(); m_devicePath = object.value(QStringLiteral("device")).toString();
m_separateScreens = object.value(QStringLiteral("separateScreens")).toBool(m_separateScreens);
const QJsonArray outputs = object.value(QStringLiteral("outputs")).toArray(); const QJsonArray outputs = object.value(QStringLiteral("outputs")).toArray();
for (int i = 0; i < outputs.size(); i++) { for (int i = 0; i < outputs.size(); i++) {
@ -254,6 +262,7 @@ void QEglFSKmsIntegration::loadConfig()
qCDebug(qLcEglfsKmsDebug) << "Configuration:\n" qCDebug(qLcEglfsKmsDebug) << "Configuration:\n"
<< "\thwcursor:" << m_hwCursor << "\n" << "\thwcursor:" << m_hwCursor << "\n"
<< "\tpbuffers:" << m_pbuffers << "\n" << "\tpbuffers:" << m_pbuffers << "\n"
<< "\tseparateScreens:" << m_separateScreens << "\n"
<< "\toutputs:" << m_outputSettings; << "\toutputs:" << m_outputSettings;
} }

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -65,6 +66,7 @@ public:
bool supportsPBuffers() const Q_DECL_OVERRIDE; bool supportsPBuffers() const Q_DECL_OVERRIDE;
bool hwCursor() const; bool hwCursor() const;
bool separateScreens() const;
QMap<QString, QVariantMap> outputSettings() const; QMap<QString, QVariantMap> outputSettings() const;
private: private:
@ -73,6 +75,7 @@ private:
QEglFSKmsDevice *m_device; QEglFSKmsDevice *m_device;
bool m_hwCursor; bool m_hwCursor;
bool m_pbuffers; bool m_pbuffers;
bool m_separateScreens;
QString m_devicePath; QString m_devicePath;
QMap<QString, QVariantMap> m_outputSettings; QMap<QString, QVariantMap> m_outputSettings;
}; };

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -120,6 +121,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
, m_cursor(Q_NULLPTR) , m_cursor(Q_NULLPTR)
, m_interruptHandler(new QEglFSKmsInterruptHandler(this)) , m_interruptHandler(new QEglFSKmsInterruptHandler(this))
{ {
m_siblings << this;
} }
QEglFSKmsScreen::~QEglFSKmsScreen() QEglFSKmsScreen::~QEglFSKmsScreen()
@ -185,6 +187,9 @@ QString QEglFSKmsScreen::name() const
QPlatformCursor *QEglFSKmsScreen::cursor() const QPlatformCursor *QEglFSKmsScreen::cursor() const
{ {
if (m_integration->hwCursor()) { if (m_integration->hwCursor()) {
if (!m_integration->separateScreens())
return m_device->globalCursor();
if (m_cursor.isNull()) { if (m_cursor.isNull()) {
QEglFSKmsScreen *that = const_cast<QEglFSKmsScreen *>(this); QEglFSKmsScreen *that = const_cast<QEglFSKmsScreen *>(this);
that->m_cursor.reset(new QEglFSKmsCursor(that)); that->m_cursor.reset(new QEglFSKmsCursor(that));

View File

@ -1,5 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
@ -85,6 +86,10 @@ public:
qreal refreshRate() const Q_DECL_OVERRIDE; qreal refreshRate() const Q_DECL_OVERRIDE;
QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; }
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
QEglFSKmsIntegration *integration() const { return m_integration; }
QEglFSKmsDevice *device() const { return m_device; } QEglFSKmsDevice *device() const { return m_device; }
gbm_surface *surface() const { return m_gbm_surface; } gbm_surface *surface() const { return m_gbm_surface; }
@ -110,6 +115,8 @@ private:
QPoint m_pos; QPoint m_pos;
QScopedPointer<QEglFSKmsCursor> m_cursor; QScopedPointer<QEglFSKmsCursor> m_cursor;
QList<QPlatformScreen *> m_siblings;
struct FrameBuffer { struct FrameBuffer {
FrameBuffer() : fb(0) {} FrameBuffer() : fb(0) {}
uint32_t fb; uint32_t fb;