diff --git a/src/backends/drm/drm_commit_thread.cpp b/src/backends/drm/drm_commit_thread.cpp index 5123d2d7ba..776d0bdbb4 100644 --- a/src/backends/drm/drm_commit_thread.cpp +++ b/src/backends/drm/drm_commit_thread.cpp @@ -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 committed(static_cast(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 &&commit) diff --git a/src/backends/drm/drm_commit_thread.h b/src/backends/drm/drm_commit_thread.h index a348b9bbee..e39a3dd24d 100644 --- a/src/backends/drm/drm_commit_thread.h +++ b/src/backends/drm/drm_commit_thread.h @@ -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 &&commit); diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index f757d46d42..e69b21bce6 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -40,7 +40,7 @@ static const QMap> legacyCursorFormats = {{DRM_FORMAT_ DrmPipeline::DrmPipeline(DrmConnector *conn) : m_connector(conn) - , m_commitThread(std::make_unique(conn->connectorName())) + , m_commitThread(std::make_unique(conn->gpu(), conn->connectorName())) { QObject::connect(m_commitThread.get(), &DrmCommitThread::commitFailed, [this]() { if (m_output) {