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
This commit is contained in:
parent
bf17d6388c
commit
5007d337b3
3 changed files with 30 additions and 24 deletions
|
@ -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<DrmAtomicCommit> &&commit)
|
||||
void DrmCommitThread::addCommit(std::unique_ptr<DrmAtomicCommit> &&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<DrmAtomicCommit> &&commit)
|
|||
m_commitPending.notify_all();
|
||||
}
|
||||
|
||||
bool DrmCommitThread::replaceCommit(std::unique_ptr<DrmAtomicCommit> &&commit)
|
||||
bool DrmCommitThread::updateCommit(std::unique_ptr<DrmAtomicCommit> &&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;
|
||||
|
|
|
@ -29,8 +29,8 @@ public:
|
|||
explicit DrmCommitThread();
|
||||
~DrmCommitThread();
|
||||
|
||||
void setCommit(std::unique_ptr<DrmAtomicCommit> &&commit);
|
||||
bool replaceCommit(std::unique_ptr<DrmAtomicCommit> &&commit);
|
||||
void addCommit(std::unique_ptr<DrmAtomicCommit> &&commit);
|
||||
bool updateCommit(std::unique_ptr<DrmAtomicCommit> &&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<DrmAtomicCommit> m_commit;
|
||||
std::vector<std::unique_ptr<DrmAtomicCommit>> m_commits;
|
||||
std::unique_ptr<QThread> m_thread;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_commitPending;
|
||||
|
|
|
@ -175,7 +175,7 @@ DrmPipeline::Error DrmPipeline::commitPipelinesAtomic(const QVector<DrmPipeline
|
|||
Q_ASSERT(pipelines.size() == 1);
|
||||
Q_ASSERT(unusedObjects.isEmpty());
|
||||
const auto pipeline = pipelines.front();
|
||||
pipeline->m_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 QVector<DrmPipeline
|
|||
return errnoToError();
|
||||
}
|
||||
const auto pipeline = pipelines.front();
|
||||
if (pipeline->m_commitThread->replaceCommit(std::move(commit))) {
|
||||
if (pipeline->m_commitThread->updateCommit(std::move(commit))) {
|
||||
pipeline->atomicCommitSuccessful();
|
||||
}
|
||||
return Error::None;
|
||||
|
|
Loading…
Reference in a new issue