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:
parent
1c8bd1be62
commit
14749e91e9
3 changed files with 29 additions and 7 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue