diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-08-04 13:31:20 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2017-09-05 10:30:50 +0000 |
commit | cf24d203850cd87e31bc123407e7ae126be9961c (patch) | |
tree | 52bbf250df26c320b706f2cfff6fc028cfef2ea3 /src/platformsupport/kmsconvenience/qkmsdevice.cpp | |
parent | f2289bbcbbbddfd248c5e0858e148d7cc7336f8a (diff) |
eglfs_kms: Add headless mode for DRM render nodes
Attempting to switch /dev/dri/cardX to /dev/dri/renderDY is futile
on its own now since many output-related drm operations fail and we
eventually crash.
Add a new headless mode that skips the real screen stuff and registers
a fairly dummy, headless screen, does not bother with the mouse cursor,
and disallows rendering to the screen via a QWindow (while keeping the
actual rendering still fully functional).
Such applications will not need any special privileges and will run even
if there is a DRM master (X11, Wayland compositor) active.
For example the configuration can look like this:
{
"device": "/dev/dri/renderD128",
"headless": "1024x768"
}
After this applications have two choices to perform offscreen
rendering:
1. Use an ordinary window (and its default framebuffer, meaning the
gbm_surface), e.g. a QOpenGLWindow subclass
MyOpenGLWindow w;
w.show(); // will not actually show on screen
w.grabFramebuffer().save("output.png");
Note that there is no vsync-based throttling. Also note that windows are
still sized to match the screen size, hence the need for specifying a size
in the headless property.
2. Or the typical offscreen approach with an extra FBO
QOffscreenSurface s;
s.setFormat(ctx.format());
s.create();
ctx.makeCurrent(&s0;
QOpenGLFramebufferObject fbo(1024, 768);
fbo.bind();
ctx.functions()->glClearColor(1, 0, 0, 1);
ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
fbo.toImage().save("output.png");
ctx.doneCurrent();
Task-number: QTBUG-62262
Change-Id: Ic1dbfa2b27b223bd5ef8ba36b665f0f61abf4f06
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/platformsupport/kmsconvenience/qkmsdevice.cpp')
-rw-r--r-- | src/platformsupport/kmsconvenience/qkmsdevice.cpp | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp index 401a2aec81..753fdb07af 100644 --- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp +++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Copyright (C) 2016 Pelagicore AG ** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> ** Contact: https://www.qt.io/licensing/ @@ -179,7 +179,7 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources, drmModeModeInfo configurationModeline; auto userConfig = m_screenConfig->outputSettings(); - auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName)); + QVariantMap 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(); @@ -489,9 +489,22 @@ static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b void QKmsDevice::createScreens() { + // Headless mode using a render node: cannot do any output related DRM + // stuff. Skip it all and register a dummy screen. + if (m_screenConfig->headless()) { + QPlatformScreen *screen = createHeadlessScreen(); + if (screen) { + qCDebug(qLcKmsDebug, "Headless mode enabled"); + registerScreen(screen, true, QPoint(0, 0), QList<QPlatformScreen *>()); + return; + } else { + qWarning("QKmsDevice: Requested headless mode without support in the backend. Request is ignored."); + } + } + drmModeResPtr resources = drmModeGetResources(m_dri_fd); if (!resources) { - qWarning("drmModeGetResources failed"); + qErrnoWarning(errno, "drmModeGetResources failed"); return; } @@ -597,6 +610,12 @@ void QKmsDevice::createScreens() } } +QPlatformScreen *QKmsDevice::createHeadlessScreen() +{ + // headless mode not supported by default + return nullptr; +} + // not all subclasses support screen cloning void QKmsDevice::registerScreenCloning(QPlatformScreen *screen, QPlatformScreen *screenThisScreenClones, @@ -628,7 +647,8 @@ QKmsScreenConfig *QKmsDevice::screenConfig() const } QKmsScreenConfig::QKmsScreenConfig() - : m_hwCursor(true) + : m_headless(false) + , m_hwCursor(true) , m_separateScreens(false) , m_pbuffers(false) , m_virtualDesktopLayout(VirtualDesktopLayoutHorizontal) @@ -663,6 +683,16 @@ void QKmsScreenConfig::loadConfig() const QJsonObject object = doc.object(); + const QString headlessStr = object.value(QLatin1String("headless")).toString(); + const QByteArray headless = headlessStr.toUtf8(); + QSize headlessSize; + if (sscanf(headless.constData(), "%dx%d", &headlessSize.rwidth(), &headlessSize.rheight()) == 2) { + m_headless = true; + m_headlessSize = headlessSize; + } else { + m_headless = false; + } + m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor); m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers); m_devicePath = object.value(QLatin1String("device")).toString(); @@ -694,6 +724,7 @@ void QKmsScreenConfig::loadConfig() } qCDebug(qLcKmsDebug) << "Requested configuration (some settings may be ignored):\n" + << "\theadless:" << m_headless << "\n" << "\thwcursor:" << m_hwCursor << "\n" << "\tpbuffers:" << m_pbuffers << "\n" << "\tseparateScreens:" << m_separateScreens << "\n" |