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.
** Contact: http://www.qt.io/licensing/
**
@ -87,8 +88,11 @@ QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
QEglFSKmsCursor::~QEglFSKmsCursor()
{
drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0);
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
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);
m_bo = Q_NULLPTR;
@ -143,10 +147,15 @@ void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
gbm_bo_write(m_bo, cursorImage.constBits(), cursorImage.byteCount());
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());
if (status != 0)
qWarning("Could not set cursor: %d", status);
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
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
@ -157,12 +166,17 @@ QPoint QEglFSKmsCursor::pos() const
void QEglFSKmsCursor::setPos(const QPoint &pos)
{
QPoint adjustedPos = pos - m_cursorImage.hotspot();
int ret = drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, adjustedPos.x(), adjustedPos.y());
if (ret == 0) {
m_pos = pos;
} else {
qWarning("Failed to move cursor: %d", ret);
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();
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));
if (!file.open(QFile::ReadOnly)) {
drmModeSetCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0, 0);
drmModeMoveCursor(m_screen->device()->fd(), m_screen->output().crtc_id, 0, 0);
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
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;
return;
}

View File

@ -1,5 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
@ -308,6 +309,7 @@ QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QStrin
, m_gbm_device(Q_NULLPTR)
, m_crtc_allocator(0)
, m_connector_allocator(0)
, m_globalCursor(Q_NULLPTR)
{
}
@ -347,6 +349,10 @@ void QEglFSKmsDevice::close()
qt_safe_close(m_dri_fd);
m_dri_fd = -1;
}
if (m_globalCursor)
m_globalCursor->deleteLater();
m_globalCursor = Q_NULLPTR;
}
void QEglFSKmsDevice::createScreens()
@ -357,6 +363,8 @@ void QEglFSKmsDevice::createScreens()
return;
}
QEglFSKmsScreen *primaryScreen = Q_NULLPTR;
QList<QPlatformScreen *> siblings;
QPoint pos(0, 0);
QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
@ -369,12 +377,24 @@ void QEglFSKmsDevice::createScreens()
if (screen) {
integration->addScreen(screen);
pos.rx() += screen->geometry().width();
siblings << screen;
if (!primaryScreen)
primaryScreen = screen;
}
drmModeFreeConnector(connector);
}
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
@ -387,6 +407,11 @@ int QEglFSKmsDevice::fd() const
return m_dri_fd;
}
QPlatformCursor *QEglFSKmsDevice::globalCursor() const
{
return m_globalCursor;
}
void QEglFSKmsDevice::handleDrmEvent()
{
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.
** Contact: http://www.qt.io/licensing/
**
@ -34,6 +35,7 @@
#ifndef QEGLFSKMSDEVICE_H
#define QEGLFSKMSDEVICE_H
#include "qeglfskmscursor.h"
#include "qeglfskmsintegration.h"
#include <xf86drm.h>
@ -57,6 +59,8 @@ public:
gbm_device *device() const;
int fd() const;
QPlatformCursor *globalCursor() const;
void handleDrmEvent();
private:
@ -70,6 +74,8 @@ private:
quint32 m_crtc_allocator;
quint32 m_connector_allocator;
QEglFSKmsCursor *m_globalCursor;
int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
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.
** Contact: http://www.qt.io/licensing/
**
@ -60,6 +61,7 @@ QEglFSKmsIntegration::QEglFSKmsIntegration()
: m_device(Q_NULLPTR)
, m_hwCursor(true)
, m_pbuffers(false)
, m_separateScreens(false)
{}
void QEglFSKmsIntegration::platformInit()
@ -203,6 +205,11 @@ bool QEglFSKmsIntegration::hwCursor() const
return m_hwCursor;
}
bool QEglFSKmsIntegration::separateScreens() const
{
return m_separateScreens;
}
QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const
{
return m_outputSettings;
@ -235,6 +242,7 @@ void QEglFSKmsIntegration::loadConfig()
m_hwCursor = object.value(QStringLiteral("hwcursor")).toBool(m_hwCursor);
m_pbuffers = object.value(QStringLiteral("pbuffers")).toBool(m_pbuffers);
m_devicePath = object.value(QStringLiteral("device")).toString();
m_separateScreens = object.value(QStringLiteral("separateScreens")).toBool(m_separateScreens);
const QJsonArray outputs = object.value(QStringLiteral("outputs")).toArray();
for (int i = 0; i < outputs.size(); i++) {
@ -254,6 +262,7 @@ void QEglFSKmsIntegration::loadConfig()
qCDebug(qLcEglfsKmsDebug) << "Configuration:\n"
<< "\thwcursor:" << m_hwCursor << "\n"
<< "\tpbuffers:" << m_pbuffers << "\n"
<< "\tseparateScreens:" << m_separateScreens << "\n"
<< "\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.
** Contact: http://www.qt.io/licensing/
**
@ -65,6 +66,7 @@ public:
bool supportsPBuffers() const Q_DECL_OVERRIDE;
bool hwCursor() const;
bool separateScreens() const;
QMap<QString, QVariantMap> outputSettings() const;
private:
@ -73,6 +75,7 @@ private:
QEglFSKmsDevice *m_device;
bool m_hwCursor;
bool m_pbuffers;
bool m_separateScreens;
QString m_devicePath;
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.
** Contact: http://www.qt.io/licensing/
**
@ -120,6 +121,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
, m_cursor(Q_NULLPTR)
, m_interruptHandler(new QEglFSKmsInterruptHandler(this))
{
m_siblings << this;
}
QEglFSKmsScreen::~QEglFSKmsScreen()
@ -185,6 +187,9 @@ QString QEglFSKmsScreen::name() const
QPlatformCursor *QEglFSKmsScreen::cursor() const
{
if (m_integration->hwCursor()) {
if (!m_integration->separateScreens())
return m_device->globalCursor();
if (m_cursor.isNull()) {
QEglFSKmsScreen *that = const_cast<QEglFSKmsScreen *>(this);
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.
** Contact: http://www.qt.io/licensing/
**
@ -85,6 +86,10 @@ public:
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; }
gbm_surface *surface() const { return m_gbm_surface; }
@ -110,6 +115,8 @@ private:
QPoint m_pos;
QScopedPointer<QEglFSKmsCursor> m_cursor;
QList<QPlatformScreen *> m_siblings;
struct FrameBuffer {
FrameBuffer() : fb(0) {}
uint32_t fb;