backends/drm: try to handle page flips timing out

While this should really never happen in the first place, if the kernel still accepts
atomic commits, this is better than the screen(s) freezing and never recovering.

BUG: 480895
This commit is contained in:
Xaver Hugl 2024-02-05 19:28:15 +01:00
parent 1c8bd1be62
commit 14749e91e9
3 changed files with 29 additions and 7 deletions

View file

@ -17,8 +17,16 @@ using namespace std::chrono_literals;
namespace KWin
{
DrmCommitThread::DrmCommitThread(const QString &name)
/**
* This should always be longer than any real pageflip can take, even with PSR and modesets
*/
static constexpr auto s_pageflipTimeout = 5s;
DrmCommitThread::DrmCommitThread(DrmGpu *gpu, const QString &name)
{
if (!gpu->atomicModeSetting()) {
return;
}
m_thread.reset(QThread::create([this]() {
const auto thread = QThread::currentThread();
gainRealTime();
@ -27,11 +35,23 @@ DrmCommitThread::DrmCommitThread(const QString &name)
return;
}
std::unique_lock lock(m_mutex);
if (m_commits.empty() || m_committed) {
bool timeout = false;
if (m_committed) {
timeout = m_commitPending.wait_for(lock, s_pageflipTimeout) == std::cv_status::timeout;
} else if (m_commits.empty()) {
m_commitPending.wait(lock);
}
if (m_committed) {
// the commit would fail with EBUSY, wait until the pageflip is done
if (timeout) {
qCCritical(KWIN_DRM, "Pageflip timed out! This is a kernel bug");
std::unique_ptr<DrmAtomicCommit> committed(static_cast<DrmAtomicCommit *>(m_committed.release()));
const bool cursorOnly = committed->isCursorOnly();
m_droppedCommits.push_back(std::move(committed));
if (!cursorOnly) {
QMetaObject::invokeMethod(this, &DrmCommitThread::commitFailed, Qt::ConnectionType::QueuedConnection);
}
}
continue;
}
if (!m_commits.empty()) {
@ -187,9 +207,11 @@ void DrmCommitThread::optimizeCommits()
DrmCommitThread::~DrmCommitThread()
{
m_thread->requestInterruption();
m_commitPending.notify_all();
m_thread->wait();
if (m_thread) {
m_thread->requestInterruption();
m_commitPending.notify_all();
m_thread->wait();
}
}
void DrmCommitThread::addCommit(std::unique_ptr<DrmAtomicCommit> &&commit)

View file

@ -28,7 +28,7 @@ class DrmCommitThread : public QObject
{
Q_OBJECT
public:
explicit DrmCommitThread(const QString &name);
explicit DrmCommitThread(DrmGpu *gpu, const QString &name);
~DrmCommitThread();
void addCommit(std::unique_ptr<DrmAtomicCommit> &&commit);

View file

@ -40,7 +40,7 @@ static const QMap<uint32_t, QList<uint64_t>> legacyCursorFormats = {{DRM_FORMAT_
DrmPipeline::DrmPipeline(DrmConnector *conn)
: m_connector(conn)
, m_commitThread(std::make_unique<DrmCommitThread>(conn->connectorName()))
, m_commitThread(std::make_unique<DrmCommitThread>(conn->gpu(), conn->connectorName()))
{
QObject::connect(m_commitThread.get(), &DrmCommitThread::commitFailed, [this]() {
if (m_output) {