eglfs: Configurable screen order in the virtual desktop
Say one wants a virtual desktop with the display on HDMI above the display on DisplayPort: { "device": "drm-nvdc", "virtualDesktopOrientation": "vertical", "outputs": [ { "name": "HDMI1", "virtualIndex": 0 }, { "name": "DP1" } ] } Undefined virtualIndex values map to INT_MAX and will go after the explicitly specified ones. However, the sorting is stable so the original order from the DRM connector list is preserved between such outputs. Task-number: QTBUG-55188 Change-Id: I204fb08205ea7dbfbcdefd1d22ed22f5387f3e8c Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
parent
ce2419af89
commit
2afead0211
@ -142,10 +142,10 @@ void QEglFSKmsGbmDevice::handleDrmEvent()
|
||||
drmHandleEvent(fd(), &drmEvent);
|
||||
}
|
||||
|
||||
QEglFSKmsScreen *QEglFSKmsGbmDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
|
||||
QEglFSKmsScreen *QEglFSKmsGbmDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
|
||||
{
|
||||
static bool firstScreen = true;
|
||||
QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(integration, device, output, position);
|
||||
QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(integration, device, output);
|
||||
|
||||
if (firstScreen && integration->hwCursor()) {
|
||||
m_globalCursor = new QEglFSKmsGbmCursor(screen);
|
||||
|
@ -68,8 +68,7 @@ public:
|
||||
|
||||
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position) Q_DECL_OVERRIDE;
|
||||
QEglFSKmsOutput output) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QEglFSKmsGbmDevice)
|
||||
|
@ -93,10 +93,9 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
|
||||
}
|
||||
|
||||
QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position)
|
||||
: QEglFSKmsScreen(integration, device, output, position)
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output)
|
||||
: QEglFSKmsScreen(integration, device, output)
|
||||
, m_gbm_surface(Q_NULLPTR)
|
||||
, m_gbm_bo_current(Q_NULLPTR)
|
||||
, m_gbm_bo_next(Q_NULLPTR)
|
||||
|
@ -55,9 +55,8 @@ class QEglFSKmsGbmScreen : public QEglFSKmsScreen
|
||||
{
|
||||
public:
|
||||
QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position);
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output);
|
||||
~QEglFSKmsGbmScreen();
|
||||
|
||||
QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
|
||||
|
@ -83,9 +83,9 @@ EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const
|
||||
}
|
||||
|
||||
QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output, QPoint position)
|
||||
QEglFSKmsOutput output)
|
||||
{
|
||||
QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(integration, device, output, position);
|
||||
QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(integration, device, output);
|
||||
|
||||
if (!m_globalCursor && !integration->separateScreens()) {
|
||||
qCDebug(qLcEglfsKmsDebug, "Creating new global mouse cursor");
|
||||
|
@ -58,8 +58,7 @@ public:
|
||||
|
||||
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position) Q_DECL_OVERRIDE;
|
||||
QEglFSKmsOutput output) Q_DECL_OVERRIDE;
|
||||
|
||||
QPlatformCursor *globalCursor() { return m_globalCursor; }
|
||||
void destroyGlobalCursor();
|
||||
|
@ -43,8 +43,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
|
||||
: QEglFSKmsScreen(integration, device, output, position)
|
||||
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
|
||||
: QEglFSKmsScreen(integration, device, output)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,7 @@ class QEglFSKmsEglDeviceScreen : public QEglFSKmsScreen
|
||||
public:
|
||||
QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position);
|
||||
QEglFSKmsOutput output);
|
||||
~QEglFSKmsEglDeviceScreen();
|
||||
|
||||
QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
|
||||
|
@ -159,7 +159,7 @@ static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode)
|
||||
return true;
|
||||
}
|
||||
|
||||
QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos)
|
||||
QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, int *virtualIndex)
|
||||
{
|
||||
const QByteArray connectorName = nameForConnector(connector);
|
||||
|
||||
@ -192,6 +192,8 @@ QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resourc
|
||||
qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData());
|
||||
configuration = OutputConfigPreferred;
|
||||
}
|
||||
if (virtualIndex)
|
||||
*virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt();
|
||||
|
||||
const uint32_t crtc_id = resources->crtcs[crtc];
|
||||
|
||||
@ -303,6 +305,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resourc
|
||||
physSize.setHeight(connector->mmHeight);
|
||||
}
|
||||
}
|
||||
qCDebug(qLcEglfsKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName;
|
||||
|
||||
QEglFSKmsOutput output = {
|
||||
QString::fromUtf8(connectorName),
|
||||
@ -320,7 +323,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resourc
|
||||
m_crtc_allocator |= (1 << output.crtc_id);
|
||||
m_connector_allocator |= (1 << output.connector_id);
|
||||
|
||||
return createScreen(m_integration, this, output, pos);
|
||||
return createScreen(m_integration, this, output);
|
||||
}
|
||||
|
||||
drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
|
||||
@ -352,6 +355,26 @@ QEglFSKmsDevice::~QEglFSKmsDevice()
|
||||
{
|
||||
}
|
||||
|
||||
struct OrderedScreen
|
||||
{
|
||||
OrderedScreen() : screen(nullptr), index(-1) { }
|
||||
OrderedScreen(QEglFSKmsScreen *screen, int index) : screen(screen), index(index) { }
|
||||
QEglFSKmsScreen *screen;
|
||||
int index;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug dbg, const OrderedScreen &s)
|
||||
{
|
||||
QDebugStateSaver saver(dbg);
|
||||
dbg.nospace() << "OrderedScreen(" << s.screen << " : " << s.index << ")";
|
||||
return dbg;
|
||||
}
|
||||
|
||||
static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b)
|
||||
{
|
||||
return a.index < b.index;
|
||||
}
|
||||
|
||||
void QEglFSKmsDevice::createScreens()
|
||||
{
|
||||
drmModeResPtr resources = drmModeGetResources(m_dri_fd);
|
||||
@ -360,38 +383,46 @@ void QEglFSKmsDevice::createScreens()
|
||||
return;
|
||||
}
|
||||
|
||||
QEglFSKmsScreen *primaryScreen = Q_NULLPTR;
|
||||
QList<QPlatformScreen *> siblings;
|
||||
QPoint pos(0, 0);
|
||||
QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
|
||||
QVector<OrderedScreen> screens;
|
||||
|
||||
for (int i = 0; i < resources->count_connectors; i++) {
|
||||
drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
|
||||
if (!connector)
|
||||
continue;
|
||||
|
||||
QEglFSKmsScreen *screen = createScreenForConnector(resources, connector, pos);
|
||||
if (screen) {
|
||||
integration->addScreen(screen);
|
||||
|
||||
if (m_integration->virtualDesktopLayout() == QEglFSKmsIntegration::VirtualDesktopLayoutVertical)
|
||||
pos.ry() += screen->geometry().height();
|
||||
else
|
||||
pos.rx() += screen->geometry().width();
|
||||
|
||||
siblings << screen;
|
||||
|
||||
if (!primaryScreen)
|
||||
primaryScreen = screen;
|
||||
}
|
||||
int virtualIndex;
|
||||
QEglFSKmsScreen *screen = createScreenForConnector(resources, connector, &virtualIndex);
|
||||
if (screen)
|
||||
screens.append(OrderedScreen(screen, virtualIndex));
|
||||
|
||||
drmModeFreeConnector(connector);
|
||||
}
|
||||
|
||||
drmModeFreeResources(resources);
|
||||
|
||||
// Use stable sort to preserve the original order for outputs with unspecified indices.
|
||||
std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan);
|
||||
qCDebug(qLcEglfsKmsDebug) << "Sorted screen list:" << screens;
|
||||
|
||||
QPoint pos(0, 0);
|
||||
QList<QPlatformScreen *> siblings;
|
||||
QEglFSIntegration *qpaIntegration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
|
||||
|
||||
for (const OrderedScreen &orderedScreen : screens) {
|
||||
QEglFSKmsScreen *s = orderedScreen.screen;
|
||||
// set up a horizontal or vertical virtual desktop
|
||||
s->setVirtualPosition(pos);
|
||||
if (m_integration->virtualDesktopLayout() == QEglFSKmsIntegration::VirtualDesktopLayoutVertical)
|
||||
pos.ry() += s->geometry().height();
|
||||
else
|
||||
pos.rx() += s->geometry().width();
|
||||
qCDebug(qLcEglfsKmsDebug) << "Adding screen" << s << "to QPA with geometry" << s->geometry();
|
||||
qpaIntegration->addScreen(s);
|
||||
siblings << s;
|
||||
}
|
||||
|
||||
if (!m_integration->separateScreens()) {
|
||||
// set up a virtual desktop
|
||||
// enable the virtual desktop
|
||||
Q_FOREACH (QPlatformScreen *screen, siblings)
|
||||
static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings);
|
||||
}
|
||||
@ -407,9 +438,9 @@ QString QEglFSKmsDevice::devicePath() const
|
||||
return m_path;
|
||||
}
|
||||
|
||||
QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
|
||||
QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
|
||||
{
|
||||
return new QEglFSKmsScreen(integration, device, output, position);
|
||||
return new QEglFSKmsScreen(integration, device, output);
|
||||
}
|
||||
|
||||
void QEglFSKmsDevice::setFd(int fd)
|
||||
|
@ -68,8 +68,7 @@ public:
|
||||
protected:
|
||||
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position);
|
||||
QEglFSKmsOutput output);
|
||||
void setFd(int fd);
|
||||
|
||||
QEglFSKmsIntegration *m_integration;
|
||||
@ -80,7 +79,7 @@ protected:
|
||||
quint32 m_connector_allocator;
|
||||
|
||||
int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
|
||||
QEglFSKmsScreen *createScreenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos);
|
||||
QEglFSKmsScreen *createScreenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, int *virtualIndex);
|
||||
drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);
|
||||
|
||||
static void pageFlipHandler(int fd,
|
||||
|
@ -201,7 +201,7 @@ void QEglFSKmsIntegration::loadConfig()
|
||||
else if (vdOriString == QLatin1String("vertical"))
|
||||
m_virtualDesktopLayout = VirtualDesktopLayoutVertical;
|
||||
else
|
||||
qCWarning(qLcEglfsKmsDebug) << "Unknown virtualDesktop value" << vdOriString;
|
||||
qCWarning(qLcEglfsKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString;
|
||||
}
|
||||
|
||||
const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray();
|
||||
|
@ -71,13 +71,11 @@ private:
|
||||
|
||||
QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position)
|
||||
QEglFSKmsOutput output)
|
||||
: QEglFSScreen(eglGetDisplay(device->nativeDisplay()))
|
||||
, m_integration(integration)
|
||||
, m_device(device)
|
||||
, m_output(output)
|
||||
, m_pos(position)
|
||||
, m_powerState(PowerStateOn)
|
||||
, m_interruptHandler(new QEglFSKmsInterruptHandler(this))
|
||||
{
|
||||
@ -98,34 +96,19 @@ QEglFSKmsScreen::~QEglFSKmsScreen()
|
||||
delete m_interruptHandler;
|
||||
}
|
||||
|
||||
void QEglFSKmsScreen::setVirtualPosition(const QPoint &pos)
|
||||
{
|
||||
m_pos = pos;
|
||||
}
|
||||
|
||||
// Reimplement rawGeometry(), not geometry(). The base class implementation of
|
||||
// geometry() calls rawGeometry() and may apply additional transforms.
|
||||
QRect QEglFSKmsScreen::rawGeometry() const
|
||||
{
|
||||
const int mode = m_output.mode;
|
||||
QRect r(m_pos.x(), m_pos.y(),
|
||||
m_output.modes[mode].hdisplay,
|
||||
m_output.modes[mode].vdisplay);
|
||||
|
||||
static int rotation = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION");
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
case 180:
|
||||
case -180:
|
||||
break;
|
||||
case 90:
|
||||
case -90: {
|
||||
int h = r.height();
|
||||
r.setHeight(r.width());
|
||||
r.setWidth(h);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qWarning("Invalid rotation %d specified in QT_QPA_EGLFS_ROTATION", rotation);
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
return QRect(m_pos.x(), m_pos.y(),
|
||||
m_output.modes[mode].hdisplay,
|
||||
m_output.modes[mode].vdisplay);
|
||||
}
|
||||
|
||||
int QEglFSKmsScreen::depth() const
|
||||
|
@ -74,11 +74,13 @@ class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
|
||||
public:
|
||||
QEglFSKmsScreen(QEglFSKmsIntegration *integration,
|
||||
QEglFSKmsDevice *device,
|
||||
QEglFSKmsOutput output,
|
||||
QPoint position);
|
||||
QEglFSKmsOutput output);
|
||||
~QEglFSKmsScreen();
|
||||
|
||||
void setVirtualPosition(const QPoint &pos);
|
||||
|
||||
QRect rawGeometry() const Q_DECL_OVERRIDE;
|
||||
|
||||
int depth() const Q_DECL_OVERRIDE;
|
||||
QImage::Format format() const Q_DECL_OVERRIDE;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user