From cd9a0afafa56bd251ef48022b82dd2c037e4f3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 11 Jul 2016 11:26:03 +0200 Subject: [PATCH] [platforms/drm] Properly handle case that mapping the blank buffer fails Summary: If it's not possible to create a buffer to blank the output, KWin won't be able to render to the output. In that case the output should not be added to the list of outputs. To support this DrmOutput::blank and DrmOutput::init return bool to indicate whether they succeeded. DrmBackend handles this situation and doesn't add the output to the list of outputs if init failed. If after init there are no outputs KWin is in a state where it won't be functional. Thus the platform emits the initFailed signal to terminate. BUG: 365242 FIXED-IN: 5.7.2 Test Plan: No hardware to reproduce the condition Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2135 --- plugins/platforms/drm/drm_backend.cpp | 15 +++++++++++++-- plugins/platforms/drm/drm_output.cpp | 16 +++++++++++----- plugins/platforms/drm/drm_output.h | 4 ++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp index c15f3f4f44..fd0240f80b 100644 --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -237,6 +237,11 @@ void DrmBackend::openDrm() ); m_drmId = device->sysNum(); queryResources(); + if (m_outputs.isEmpty()) { + qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; + emit initFailed(); + return; + } // setup udevMonitor if (m_udevMonitor) { @@ -315,7 +320,11 @@ void DrmBackend::queryResources() drmOutput->m_mode = connector->modes[0]; } drmOutput->m_connector = connector->connector_id; - drmOutput->init(connector.data()); + if (!drmOutput->init(connector.data())) { + qCWarning(KWIN_DRM) << "Failed to create output for connector " << connector->connector_id; + delete drmOutput; + continue; + } qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid(); connectedOutputs << drmOutput; } @@ -339,7 +348,9 @@ void DrmBackend::queryResources() } m_outputs = connectedOutputs; readOutputsConfiguration(); - emit screensQueried(); + if (!m_outputs.isEmpty()) { + emit screensQueried(); + } } void DrmBackend::readOutputsConfiguration() diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp index 31f563d6be..69b1ed6c41 100644 --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -180,13 +180,15 @@ static DrmOutput::DpmsMode fromWaylandDpmsMode(KWayland::Server::OutputInterface } } -void DrmOutput::init(drmModeConnector *connector) +bool DrmOutput::init(drmModeConnector *connector) { initEdid(connector); initDpms(connector); initUuid(); m_savedCrtc.reset(drmModeGetCrtc(m_backend->fd(), m_crtcId)); - blank(); + if (!blank()) { + return false; + } setDpms(DpmsMode::On); if (!m_waylandOutput.isNull()) { delete m_waylandOutput.data(); @@ -287,6 +289,7 @@ void DrmOutput::init(drmModeConnector *connector) m_waylandOutput->create(); qCDebug(KWIN_DRM) << "Created OutputDevice"; m_waylandOutputDevice->create(); + return true; } void DrmOutput::initUuid() @@ -318,14 +321,17 @@ bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const && qstrcmp(mode->name, m_mode.name) == 0; } -void DrmOutput::blank() +bool DrmOutput::blank() { if (!m_blackBuffer) { m_blackBuffer = m_backend->createBuffer(size()); - m_blackBuffer->map(); + if (!m_blackBuffer->map()) { + cleanupBlackBuffer(); + return false; + } m_blackBuffer->image()->fill(Qt::black); } - setMode(m_blackBuffer); + return setMode(m_blackBuffer); } bool DrmOutput::setMode(DrmBuffer *buffer) diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h index e021f60017..628bb5da95 100644 --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -61,9 +61,9 @@ public: void moveCursor(const QPoint &globalPos); bool present(DrmBuffer *buffer); void pageFlipped(); - void init(drmModeConnector *connector); + bool init(drmModeConnector *connector); void restoreSaved(); - void blank(); + bool blank(); /** * This sets the changes and tests them against the DRM output