From 886773eef2cef3f50e580f6210e32650f26cd9a2 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 3 Aug 2017 13:01:38 +0200 Subject: eglfs_kms: Output cloning support { "device": "/dev/dri/card0", "outputs": [ { "name": "HDMI1", "mode": "1920x1080" }, { "name": "DP1", "mode": "1920x1080", "clones": "HDMI1" } ] } Here, assuming the QScreen for DP1 is unused and the resolution is the same, DP1 will simply mirror whatever is on HDMI1. The plane-based mouse cursor is not currently supported. Same goes for any form of scaling since this simply scans out the same framebuffer on all target CRTCs. Task-number: QTBUG-62262 Change-Id: I391be204264284a1bff752ebc2a1dbe5c8592013 Reviewed-by: Andy Nichols --- src/platformsupport/kmsconvenience/qkmsdevice.cpp | 108 +++++++++++++++------- 1 file changed, 75 insertions(+), 33 deletions(-) (limited to 'src/platformsupport/kmsconvenience/qkmsdevice.cpp') diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index d8eb2f11de..8d8be4a919 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -162,8 +162,9 @@ static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode) QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, - VirtualDesktopInfo *vinfo) + ScreenInfo *vinfo) { + Q_ASSERT(vinfo); const QByteArray connectorName = nameForConnector(connector); const int crtc = crtcForConnector(resources, connector); @@ -200,18 +201,17 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData()); configuration = OutputConfigPreferred; } - if (vinfo) { - *vinfo = VirtualDesktopInfo(); - vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt(); - if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) { - const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray(); - const QByteArrayList vposComp = vpos.split(','); - if (vposComp.count() == 2) - vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt()); - } - if (userConnectorConfig.value(QStringLiteral("primary")).toBool()) - vinfo->isPrimary = true; + + *vinfo = ScreenInfo(); + vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt(); + if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) { + const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray(); + const QByteArrayList vposComp = vpos.split(','); + if (vposComp.count() == 2) + vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt()); } + if (userConnectorConfig.value(QStringLiteral("primary")).toBool()) + vinfo->isPrimary = true; const uint32_t crtc_id = resources->crtcs[crtc]; @@ -359,24 +359,28 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, drmFormat = DRM_FORMAT_XRGB8888; } - QKmsOutput output = { - QString::fromUtf8(connectorName), - connector->connector_id, - crtc_id, - physSize, - preferred >= 0 ? preferred : selected_mode, - selected_mode, - false, // mode_set - drmModeGetCrtc(m_dri_fd, crtc_id), // saved_crtc - modes, - connector->subpixel, - connectorProperty(connector, QByteArrayLiteral("DPMS")), - connectorPropertyBlob(connector, QByteArrayLiteral("EDID")), - false, // wants_plane - 0, // plane_id - false, // plane_set - drmFormat - }; + const QString cloneSource = userConnectorConfig.value(QStringLiteral("clones")).toString(); + if (!cloneSource.isEmpty()) + qCDebug(qLcKmsDebug) << "Output" << connectorName << " clones output " << cloneSource; + + QKmsOutput output; + output.name = QString::fromUtf8(connectorName); + output.connector_id = connector->connector_id; + output.crtc_id = crtc_id; + output.physical_size = physSize; + output.preferred_mode = preferred >= 0 ? preferred : selected_mode; + output.mode = selected_mode; + output.mode_set = false; + output.saved_crtc = drmModeGetCrtc(m_dri_fd, crtc_id); + output.modes = modes; + output.subpixel = connector->subpixel; + output.dpms_prop = connectorProperty(connector, QByteArrayLiteral("DPMS")); + output.edid_blob = connectorPropertyBlob(connector, QByteArrayLiteral("EDID")); + output.wants_plane = false; + output.plane_id = 0; + output.plane_set = false; + output.drm_format = drmFormat; + output.clone_source = cloneSource; bool ok; int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok); @@ -401,6 +405,8 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, m_crtc_allocator |= (1 << output.crtc_id); m_connector_allocator |= (1 << output.connector_id); + vinfo->output = output; + return createScreen(output); } @@ -461,10 +467,10 @@ QKmsDevice::~QKmsDevice() struct OrderedScreen { OrderedScreen() : screen(nullptr) { } - OrderedScreen(QPlatformScreen *screen, const QKmsDevice::VirtualDesktopInfo &vinfo) + OrderedScreen(QPlatformScreen *screen, const QKmsDevice::ScreenInfo &vinfo) : screen(screen), vinfo(vinfo) { } QPlatformScreen *screen; - QKmsDevice::VirtualDesktopInfo vinfo; + QKmsDevice::ScreenInfo vinfo; }; QDebug operator<<(QDebug dbg, const OrderedScreen &s) @@ -511,7 +517,7 @@ void QKmsDevice::createScreens() if (!connector) continue; - VirtualDesktopInfo vinfo; + ScreenInfo vinfo; QPlatformScreen *screen = createScreenForConnector(resources, connector, &vinfo); if (screen) screens.append(OrderedScreen(screen, vinfo)); @@ -526,6 +532,32 @@ void QKmsDevice::createScreens() std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan); qCDebug(qLcKmsDebug) << "Sorted screen list:" << screens; + // The final list of screens is available, so do the second phase setup. + // Hook up clone sources and targets. + for (const OrderedScreen &orderedScreen : screens) { + QVector screensCloningThisScreen; + for (const OrderedScreen &s : screens) { + if (s.vinfo.output.clone_source == orderedScreen.vinfo.output.name) + screensCloningThisScreen.append(s.screen); + } + QPlatformScreen *screenThisScreenClones = nullptr; + if (!orderedScreen.vinfo.output.clone_source.isEmpty()) { + for (const OrderedScreen &s : screens) { + if (s.vinfo.output.name == orderedScreen.vinfo.output.clone_source) { + screenThisScreenClones = s.screen; + break; + } + } + } + if (screenThisScreenClones) + qCDebug(qLcKmsDebug) << orderedScreen.screen->name() << "clones" << screenThisScreenClones; + if (!screensCloningThisScreen.isEmpty()) + qCDebug(qLcKmsDebug) << orderedScreen.screen->name() << "is cloned by" << screensCloningThisScreen; + + registerScreenCloning(orderedScreen.screen, screenThisScreenClones, screensCloningThisScreen); + } + + // Figure out the virtual desktop and register the screens to QPA/QGuiApplication. QPoint pos(0, 0); QList siblings; QVector virtualPositions; @@ -567,6 +599,16 @@ void QKmsDevice::createScreens() } } +// not all subclasses support screen cloning +void QKmsDevice::registerScreenCloning(QPlatformScreen *screen, + QPlatformScreen *screenThisScreenClones, + const QVector &screensCloningThisScreen) +{ + Q_UNUSED(screen); + Q_UNUSED(screenThisScreenClones); + Q_UNUSED(screensCloningThisScreen); +} + int QKmsDevice::fd() const { return m_dri_fd; -- cgit v1.2.3