summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2016-10-04 11:29:26 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2016-11-16 10:43:53 +0000
commit2e70a86900962b1f5f6ad79ca3245bc99873d889 (patch)
treee901db7212f6ed656b0dba98e9cf3fb12850a5e6 /src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
parent25e67bcacac690be4971cfab16cd838653d0e7c6 (diff)
Move DRM/KMS code from eglfs into kmsconvenience
The generic DRM code, not involving any GBM or EGLDevice stuff, can now be reused in components outside eglfs, for example linuxfb in order to get support for DRM dumb buffers. Task-number: QTBUG-56306 Change-Id: If7dffdb2415489dbc6470782fa76efcaeccf01c7 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp')
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp429
1 files changed, 10 insertions, 419 deletions
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index f6b58d1ba6..e99a6957a8 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -1,6 +1,5 @@
/****************************************************************************
**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -41,432 +40,24 @@
#include "qeglfskmsdevice.h"
#include "qeglfskmsscreen.h"
-
-#include "qeglfsintegration_p.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qcore_unix_p.h>
+#include "private/qeglfsintegration_p.h"
#include <QtGui/private/qguiapplication_p.h>
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
-enum OutputConfiguration {
- OutputConfigOff,
- OutputConfigPreferred,
- OutputConfigCurrent,
- OutputConfigMode,
- OutputConfigModeline
-};
-
-int QEglFSKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector)
-{
- for (int i = 0; i < connector->count_encoders; i++) {
- drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]);
- if (!encoder) {
- qWarning("Failed to get encoder");
- continue;
- }
-
- quint32 possibleCrtcs = encoder->possible_crtcs;
- drmModeFreeEncoder(encoder);
-
- for (int j = 0; j < resources->count_crtcs; j++) {
- bool isPossible = possibleCrtcs & (1 << j);
- bool isAvailable = !(m_crtc_allocator & 1 << resources->crtcs[j]);
-
- if (isPossible && isAvailable)
- return j;
- }
- }
-
- return -1;
-}
-
-static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_*
- "None",
- "VGA",
- "DVI",
- "DVI",
- "DVI",
- "Composite",
- "TV",
- "LVDS",
- "CTV",
- "DIN",
- "DP",
- "HDMI",
- "HDMI",
- "TV",
- "eDP",
- "Virtual",
- "DSI"
-};
-
-static QByteArray nameForConnector(const drmModeConnectorPtr connector)
-{
- QByteArray connectorName("UNKNOWN");
-
- if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
- connectorName = connector_type_names[connector->connector_type];
-
- connectorName += QByteArray::number(connector->connector_type_id);
-
- return connectorName;
-}
-
-static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode)
-{
- char hsync[16];
- char vsync[16];
- float fclock;
-
- mode->type = DRM_MODE_TYPE_USERDEF;
- mode->hskew = 0;
- mode->vscan = 0;
- mode->vrefresh = 0;
- mode->flags = 0;
-
- if (sscanf(text.constData(), "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
- &fclock,
- &mode->hdisplay,
- &mode->hsync_start,
- &mode->hsync_end,
- &mode->htotal,
- &mode->vdisplay,
- &mode->vsync_start,
- &mode->vsync_end,
- &mode->vtotal, hsync, vsync) != 11)
- return false;
-
- mode->clock = fclock * 1000;
-
- if (strcmp(hsync, "+hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PHSYNC;
- else if (strcmp(hsync, "-hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NHSYNC;
- else
- return false;
-
- if (strcmp(vsync, "+vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PVSYNC;
- else if (strcmp(vsync, "-vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NVSYNC;
- else
- return false;
-
- return true;
-}
-
-QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resources,
- drmModeConnectorPtr connector,
- VirtualDesktopInfo *vinfo)
-{
- const QByteArray connectorName = nameForConnector(connector);
-
- const int crtc = crtcForConnector(resources, connector);
- if (crtc < 0) {
- qWarning() << "No usable crtc/encoder pair for connector" << connectorName;
- return Q_NULLPTR;
- }
-
- OutputConfiguration configuration;
- QSize configurationSize;
- drmModeModeInfo configurationModeline;
-
- auto userConfig = m_integration->outputSettings();
- auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName));
- // default to the preferred mode unless overridden in the config
- const QByteArray mode = userConnectorConfig.value(QStringLiteral("mode"), QStringLiteral("preferred"))
- .toByteArray().toLower();
- if (mode == "off") {
- configuration = OutputConfigOff;
- } else if (mode == "preferred") {
- configuration = OutputConfigPreferred;
- } else if (mode == "current") {
- configuration = OutputConfigCurrent;
- } else if (sscanf(mode.constData(), "%dx%d", &configurationSize.rwidth(), &configurationSize.rheight()) == 2) {
- configuration = OutputConfigMode;
- } else if (parseModeline(mode, &configurationModeline)) {
- configuration = OutputConfigModeline;
- } else {
- 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());
- }
- }
-
- const uint32_t crtc_id = resources->crtcs[crtc];
-
- if (configuration == OutputConfigOff) {
- qCDebug(qLcEglfsKmsDebug) << "Turning off output" << connectorName;
- drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, Q_NULLPTR);
- return Q_NULLPTR;
- }
-
- // Skip disconnected output
- if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) {
- qCDebug(qLcEglfsKmsDebug) << "Skipping disconnected output" << connectorName;
- return Q_NULLPTR;
- }
-
- // Get the current mode on the current crtc
- drmModeModeInfo crtc_mode;
- memset(&crtc_mode, 0, sizeof crtc_mode);
- if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->connector_id)) {
- drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id);
- drmModeFreeEncoder(encoder);
-
- if (!crtc)
- return Q_NULLPTR;
-
- if (crtc->mode_valid)
- crtc_mode = crtc->mode;
-
- drmModeFreeCrtc(crtc);
- }
-
- QList<drmModeModeInfo> modes;
- modes.reserve(connector->count_modes);
- qCDebug(qLcEglfsKmsDebug) << connectorName << "mode count:" << connector->count_modes;
- for (int i = 0; i < connector->count_modes; i++) {
- const drmModeModeInfo &mode = connector->modes[i];
- qCDebug(qLcEglfsKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay
- << '@' << mode.vrefresh << "hz";
- modes << connector->modes[i];
- }
-
- int preferred = -1;
- int current = -1;
- int configured = -1;
- int best = -1;
-
- for (int i = modes.size() - 1; i >= 0; i--) {
- const drmModeModeInfo &m = modes.at(i);
-
- if (configuration == OutputConfigMode &&
- m.hdisplay == configurationSize.width() &&
- m.vdisplay == configurationSize.height()) {
- configured = i;
- }
-
- if (!memcmp(&crtc_mode, &m, sizeof m))
- current = i;
-
- if (m.type & DRM_MODE_TYPE_PREFERRED)
- preferred = i;
-
- best = i;
- }
-
- if (configuration == OutputConfigModeline) {
- modes << configurationModeline;
- configured = modes.size() - 1;
- }
-
- if (current < 0 && crtc_mode.clock != 0) {
- modes << crtc_mode;
- current = mode.size() - 1;
- }
-
- if (configuration == OutputConfigCurrent)
- configured = current;
-
- int selected_mode = -1;
-
- if (configured >= 0)
- selected_mode = configured;
- else if (preferred >= 0)
- selected_mode = preferred;
- else if (current >= 0)
- selected_mode = current;
- else if (best >= 0)
- selected_mode = best;
-
- if (selected_mode < 0) {
- qWarning() << "No modes available for output" << connectorName;
- return Q_NULLPTR;
- } else {
- int width = modes[selected_mode].hdisplay;
- int height = modes[selected_mode].vdisplay;
- int refresh = modes[selected_mode].vrefresh;
- qCDebug(qLcEglfsKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height
- << '@' << refresh << "hz for output" << connectorName;
- }
-
- // physical size from connector < config values < env vars
- static const int width = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH");
- static const int height = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT");
- QSizeF physSize(width, height);
- if (physSize.isEmpty()) {
- physSize = QSize(userConnectorConfig.value(QStringLiteral("physicalWidth")).toInt(),
- userConnectorConfig.value(QStringLiteral("physicalHeight")).toInt());
- if (physSize.isEmpty()) {
- physSize.setWidth(connector->mmWidth);
- physSize.setHeight(connector->mmHeight);
- }
- }
- qCDebug(qLcEglfsKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName;
-
- QEglFSKmsOutput output = {
- QString::fromUtf8(connectorName),
- connector->connector_id,
- crtc_id,
- physSize,
- selected_mode,
- false,
- drmModeGetCrtc(m_dri_fd, crtc_id),
- modes,
- connector->subpixel,
- connectorProperty(connector, QByteArrayLiteral("DPMS"))
- };
-
- m_crtc_allocator |= (1 << output.crtc_id);
- m_connector_allocator |= (1 << output.connector_id);
-
- return createScreen(m_integration, this, output);
-}
-
-drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
-{
- drmModePropertyPtr prop;
-
- for (int i = 0; i < connector->count_props; i++) {
- prop = drmModeGetProperty(m_dri_fd, connector->props[i]);
- if (!prop)
- continue;
- if (strcmp(prop->name, name.constData()) == 0)
- return prop;
- drmModeFreeProperty(prop);
- }
-
- return Q_NULLPTR;
-}
-
-QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path)
- : m_integration(integration)
- , m_path(path)
- , m_dri_fd(-1)
- , m_crtc_allocator(0)
- , m_connector_allocator(0)
-{
-}
-
-QEglFSKmsDevice::~QEglFSKmsDevice()
-{
-}
-
-struct OrderedScreen
-{
- OrderedScreen() : screen(nullptr) { }
- OrderedScreen(QEglFSKmsScreen *screen, const QEglFSKmsDevice::VirtualDesktopInfo &vinfo)
- : screen(screen), vinfo(vinfo) { }
- QEglFSKmsScreen *screen;
- QEglFSKmsDevice::VirtualDesktopInfo vinfo;
-};
-
-QDebug operator<<(QDebug dbg, const OrderedScreen &s)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "OrderedScreen(" << s.screen << " : " << s.vinfo.virtualIndex
- << " / " << s.vinfo.virtualPos << ")";
- return dbg;
-}
-
-static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b)
-{
- return a.vinfo.virtualIndex < b.vinfo.virtualIndex;
-}
-
-void QEglFSKmsDevice::createScreens()
-{
- drmModeResPtr resources = drmModeGetResources(m_dri_fd);
- if (!resources) {
- qWarning("drmModeGetResources failed");
- return;
- }
-
- QVector<OrderedScreen> screens;
-
- for (int i = 0; i < resources->count_connectors; i++) {
- drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
- if (!connector)
- continue;
-
- VirtualDesktopInfo vinfo;
- QEglFSKmsScreen *screen = createScreenForConnector(resources, connector, &vinfo);
- if (screen)
- screens.append(OrderedScreen(screen, vinfo));
-
- 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
- if (orderedScreen.vinfo.virtualPos.isNull()) {
- s->setVirtualPosition(pos);
- if (m_integration->virtualDesktopLayout() == QEglFSKmsIntegration::VirtualDesktopLayoutVertical)
- pos.ry() += s->geometry().height();
- else
- pos.rx() += s->geometry().width();
- } else {
- s->setVirtualPosition(orderedScreen.vinfo.virtualPos);
- }
- qCDebug(qLcEglfsKmsDebug) << "Adding screen" << s << "to QPA with geometry" << s->geometry();
- // The order in qguiapp's screens list will match the order set by
- // virtualIndex. This is not only handy but also required since for instance
- // evdevtouch relies on it when performing touch device - screen mapping.
- qpaIntegration->addScreen(s);
- siblings << s;
- }
-
- if (!m_integration->separateScreens()) {
- // enable the virtual desktop
- Q_FOREACH (QPlatformScreen *screen, siblings)
- static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings);
- }
-}
-
-int QEglFSKmsDevice::fd() const
-{
- return m_dri_fd;
-}
-
-QString QEglFSKmsDevice::devicePath() const
-{
- return m_path;
-}
-
-QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
+QEglFSKmsDevice::QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path)
+ : QKmsDevice(screenConfig, path)
{
- return new QEglFSKmsScreen(integration, device, output);
}
-void QEglFSKmsDevice::setFd(int fd)
+void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings)
{
- m_dri_fd = fd;
+ QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
+ s->setVirtualPosition(virtualPos);
+ s->setVirtualSiblings(virtualSiblings);
+ static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->addScreen(s);
}
QT_END_NAMESPACE