From 26cdfd317fc87b024ebcd9c2adefc86cfd59504e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Wed, 1 Nov 2017 19:21:08 +0100 Subject: [PATCH] [platforms/drm] Restore previous mode if an atomic test fails Summary: When KWin successfully presents a new mode, it stores the current state as the last working mode. If a new modeset is requested and the atomic test fails, all is undone and reverted to this last knowing mode. Currently included are: * the mode * global position * transformation This is only done on a modeset not when going to DPMS. Test Plan: Selected the not working vertical rotation and nothing bad happened. Reviewers: #kwin, #plasma, subdiff Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D8602 --- plugins/platforms/drm/drm_object_plane.cpp | 5 +++++ plugins/platforms/drm/drm_object_plane.h | 1 + plugins/platforms/drm/drm_output.cpp | 25 +++++++++++++++++++++- plugins/platforms/drm/drm_output.h | 10 ++++++++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/plugins/platforms/drm/drm_object_plane.cpp b/plugins/platforms/drm/drm_object_plane.cpp index cd45f679b..05ec849d3 100644 --- a/plugins/platforms/drm/drm_object_plane.cpp +++ b/plugins/platforms/drm/drm_object_plane.cpp @@ -125,6 +125,11 @@ void DrmPlane::setTransformation(Transformations t) setValue(int(PropertyIndex::Rotation), int(t)); } +DrmPlane::Transformations DrmPlane::transformation() +{ + return Transformations(int(value(int(PropertyIndex::Rotation)))); +} + bool DrmPlane::atomicPopulate(drmModeAtomicReq *req) { bool ret = true; diff --git a/plugins/platforms/drm/drm_object_plane.h b/plugins/platforms/drm/drm_object_plane.h index e8f404daf..46e468b6f 100644 --- a/plugins/platforms/drm/drm_object_plane.h +++ b/plugins/platforms/drm/drm_object_plane.h @@ -91,6 +91,7 @@ public: } void setNext(DrmBuffer *b); void setTransformation(Transformations t); + Transformations transformation(); bool atomicPopulate(drmModeAtomicReq *req); void flipBuffer(); diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp index 59f941564..8231baf10 100644 --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -804,7 +804,6 @@ void DrmOutput::updateMode(int modeIndex) // nothing to do return; } - m_previousMode = m_mode; m_mode = connector->modes[modeIndex]; m_modesetRequested = true; emit modeChanged(); @@ -909,13 +908,37 @@ bool DrmOutput::presentAtomically(DrmBuffer *buffer) //TODO: When we use planes for layered rendering, fallback to renderer instead. Also for direct scanout? //TODO: Probably should undo setNext and reset the flip list qCDebug(KWIN_DRM) << "Atomic test commit failed. Aborting present."; + // go back to previous state + if (m_lastWorkingState.valid) { + m_mode = m_lastWorkingState.mode; + m_orientation = m_lastWorkingState.orientation; + setGlobalPos(m_lastWorkingState.globalPos); + if (m_primaryPlane) { + m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); + } + m_modesetRequested = true; + // TODO: forward to OutputInterface and OutputDeviceInterface + emit modeChanged(); + emit screens()->changed(); + } return false; } + const bool wasModeset = m_modesetRequested; if (!doAtomicCommit(AtomicCommitMode::Real)) { qCDebug(KWIN_DRM) << "Atomic commit failed. This should have never happened! Aborting present."; //TODO: Probably should undo setNext and reset the flip list return false; } + if (wasModeset) { + // store current mode set as new good state + m_lastWorkingState.mode = m_mode; + m_lastWorkingState.orientation = m_orientation; + m_lastWorkingState.globalPos = m_globalPos; + if (m_primaryPlane) { + m_lastWorkingState.planeTransformations = m_primaryPlane->transformation(); + } + m_lastWorkingState.valid = true; + } m_pageFlipPending = true; return true; } diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h index 876711609..856b1f150 100644 --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -22,6 +22,7 @@ along with this program. If not, see . #include "drm_pointer.h" #include "drm_object.h" +#include "drm_object_plane.h" #include #include @@ -147,7 +148,6 @@ private: qreal m_scale = 1; bool m_lastGbm = false; drmModeModeInfo m_mode; - drmModeModeInfo m_previousMode; Edid m_edid; QPointer m_waylandOutput; QPointer m_waylandOutputDevice; @@ -166,6 +166,14 @@ private: bool m_modesetRequested = true; QSize m_physicalSize; Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; + + struct { + Qt::ScreenOrientation orientation; + drmModeModeInfo mode; + DrmPlane::Transformations planeTransformations; + QPoint globalPos; + bool valid = false; + } m_lastWorkingState; }; } -- GitLab