From 5007d337b302f702188249fe7c159abb202a7a32 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Sun, 30 Jul 2023 16:56:08 +0200 Subject: [PATCH] backends/drm: queue cursor updates instead of replacing the original commit At commit time, the newest commit that's ready will be chosen, ensuring that cursor updates added just before commit time can't delay the primary plane update unnecessarily --- src/backends/drm/drm_commit_thread.cpp | 44 +++++++++++++++----------- src/backends/drm/drm_commit_thread.h | 6 ++-- src/backends/drm/drm_pipeline.cpp | 4 +-- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/backends/drm/drm_commit_thread.cpp b/src/backends/drm/drm_commit_thread.cpp index 65601e1870..46d91af283 100644 --- a/src/backends/drm/drm_commit_thread.cpp +++ b/src/backends/drm/drm_commit_thread.cpp @@ -30,19 +30,20 @@ DrmCommitThread::DrmCommitThread() return; } std::unique_lock lock(m_mutex); - if (!m_commit) { + if (m_commits.empty()) { m_commitPending.wait(lock); } - if (m_commit) { + if (!m_commits.empty()) { const auto now = std::chrono::steady_clock::now(); if (m_targetPageflipTime > now + s_safetyMargin) { lock.unlock(); std::this_thread::sleep_until(m_targetPageflipTime - s_safetyMargin); lock.lock(); } - // the other thread may replace the commit, but not erase it - Q_ASSERT(m_commit); - if (!m_commit->areBuffersReadable()) { + const auto it = std::find_if(m_commits.rbegin(), m_commits.rend(), [](const auto &commit) { + return commit->areBuffersReadable(); + }); + if (it == m_commits.rend()) { // reschedule, this commit would not hit the pageflip deadline anyways if (m_vrr) { m_targetPageflipTime += 50us; @@ -51,17 +52,23 @@ DrmCommitThread::DrmCommitThread() } continue; } - const bool vrr = m_commit->isVrr(); - if (m_commit->commit()) { + auto &commit = *it; + const bool vrr = commit->isVrr(); + const bool success = commit->commit(); + if (success) { m_vrr = vrr; // the atomic commit takes ownership of the object - m_commit.release(); - } else { - qCWarning(KWIN_DRM) << "atomic commit failed:" << strerror(errno); - m_droppedCommits.push_back(std::move(m_commit)); - QMetaObject::invokeMethod(this, &DrmCommitThread::commitFailed, Qt::ConnectionType::QueuedConnection); - QMetaObject::invokeMethod(this, &DrmCommitThread::clearDroppedCommits, Qt::ConnectionType::QueuedConnection); + commit.release(); } + for (auto &commit : m_commits) { + m_droppedCommits.push_back(std::move(commit)); + } + m_commits.clear(); + if (!success) { + qCWarning(KWIN_DRM) << "atomic commit failed:" << strerror(errno); + QMetaObject::invokeMethod(this, &DrmCommitThread::commitFailed, Qt::ConnectionType::QueuedConnection); + } + QMetaObject::invokeMethod(this, &DrmCommitThread::clearDroppedCommits, Qt::ConnectionType::QueuedConnection); } } })); @@ -75,10 +82,10 @@ DrmCommitThread::~DrmCommitThread() m_thread->wait(); } -void DrmCommitThread::setCommit(std::unique_ptr &&commit) +void DrmCommitThread::addCommit(std::unique_ptr &&commit) { std::unique_lock lock(m_mutex); - m_commit = std::move(commit); + m_commits.push_back(std::move(commit)); const auto now = std::chrono::steady_clock::now(); if (m_vrr && now >= m_lastPageflip + m_minVblankInterval) { m_targetPageflipTime = now; @@ -88,12 +95,11 @@ void DrmCommitThread::setCommit(std::unique_ptr &&commit) m_commitPending.notify_all(); } -bool DrmCommitThread::replaceCommit(std::unique_ptr &&commit) +bool DrmCommitThread::updateCommit(std::unique_ptr &&commit) { std::unique_lock lock(m_mutex); - if (m_commit) { - m_commit = std::move(commit); - m_commitPending.notify_all(); + if (!m_commits.empty()) { + m_commits.push_back(std::move(commit)); return true; } else { return false; diff --git a/src/backends/drm/drm_commit_thread.h b/src/backends/drm/drm_commit_thread.h index 2333e89b1a..5f308bbbe1 100644 --- a/src/backends/drm/drm_commit_thread.h +++ b/src/backends/drm/drm_commit_thread.h @@ -29,8 +29,8 @@ public: explicit DrmCommitThread(); ~DrmCommitThread(); - void setCommit(std::unique_ptr &&commit); - bool replaceCommit(std::unique_ptr &&commit); + void addCommit(std::unique_ptr &&commit); + bool updateCommit(std::unique_ptr &&commit); void setRefreshRate(uint32_t maximum); void pageFlipped(std::chrono::nanoseconds timestamp); @@ -42,7 +42,7 @@ private: void clearDroppedCommits(); TimePoint estimateNextVblank(TimePoint now) const; - std::unique_ptr m_commit; + std::vector> m_commits; std::unique_ptr m_thread; std::mutex m_mutex; std::condition_variable m_commitPending; diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index c76b4c4d35..e95e54811c 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -175,7 +175,7 @@ DrmPipeline::Error DrmPipeline::commitPipelinesAtomic(const QVectorm_commitThread->setCommit(std::move(commit)); + pipeline->m_commitThread->addCommit(std::move(commit)); pipeline->atomicCommitSuccessful(); return Error::None; } @@ -186,7 +186,7 @@ DrmPipeline::Error DrmPipeline::commitPipelinesAtomic(const QVectorm_commitThread->replaceCommit(std::move(commit))) { + if (pipeline->m_commitThread->updateCommit(std::move(commit))) { pipeline->atomicCommitSuccessful(); } return Error::None;