[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
icc-effect-5.14.5
Martin Flöser 2017-11-01 19:21:08 +01:00
parent b2d8bbec81
commit 26cdfd317f
4 changed files with 39 additions and 2 deletions

View File

@ -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;

View File

@ -91,6 +91,7 @@ public:
}
void setNext(DrmBuffer *b);
void setTransformation(Transformations t);
Transformations transformation();
bool atomicPopulate(drmModeAtomicReq *req);
void flipBuffer();

View File

@ -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;
}

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "drm_pointer.h"
#include "drm_object.h"
#include "drm_object_plane.h"
#include <QObject>
#include <QPoint>
@ -147,7 +148,6 @@ private:
qreal m_scale = 1;
bool m_lastGbm = false;
drmModeModeInfo m_mode;
drmModeModeInfo m_previousMode;
Edid m_edid;
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
QPointer<KWayland::Server::OutputDeviceInterface> 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;
};
}