backends/drm: Notify about failed frames if there are actually pending frames

In case a modeset needs to be performed, the drm backend will test all
pipelines to ensure that new mode won't cause any bandwidth issues on
other outputs, etc.

To do that, it may delay presenting frames. If the new configuration
doesn't work, it needs to notify about failed frames.

However, the relevant code that notifies the RenderLoop about failed
atomic commits doesn't check if there's actually a pending modeset
present.

When switching between VTs, systemd can revoke master permissions from
kwin. To make things even more trickier, kwin can try to present a frame
in that short time span.
This commit is contained in:
Vlad Zahorodnii 2021-11-25 11:15:50 +02:00
parent d92bbdb2be
commit 9f93358bc1
3 changed files with 17 additions and 11 deletions

View file

@ -727,12 +727,20 @@ bool DrmGpu::maybeModeset()
bool presentPendingForAll = std::all_of(pipelines.constBegin(), pipelines.constEnd(), [](const auto &pipeline) { bool presentPendingForAll = std::all_of(pipelines.constBegin(), pipelines.constEnd(), [](const auto &pipeline) {
return pipeline->modesetPresentPending() || !pipeline->pending.active; return pipeline->modesetPresentPending() || !pipeline->pending.active;
}); });
if (presentPendingForAll) { if (!presentPendingForAll) {
return DrmPipeline::commitPipelines(pipelines, DrmPipeline::CommitMode::CommitModeset, unusedObjects());
} else {
// commit only once all pipelines are ready for presentation // commit only once all pipelines are ready for presentation
return true; return true;
} }
const bool ok = DrmPipeline::commitPipelines(pipelines, DrmPipeline::CommitMode::CommitModeset, unusedObjects());
for (DrmPipeline *pipeline : qAsConst(pipelines)) {
if (pipeline->modesetPresentPending() && pipeline->output()) {
pipeline->resetModesetPresentPending();
if (!ok) {
pipeline->output()->presentFailed();
}
}
}
return ok;
} }
QVector<DrmObject*> DrmGpu::unusedObjects() const QVector<DrmObject*> DrmGpu::unusedObjects() const

View file

@ -126,10 +126,6 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
pipeline->pending.crtc->rollbackPending(); pipeline->pending.crtc->rollbackPending();
pipeline->pending.crtc->primaryPlane()->rollbackPending(); pipeline->pending.crtc->primaryPlane()->rollbackPending();
} }
if (mode != CommitMode::Test && pipeline->activePending() && pipeline->output()) {
pipeline->m_modesetPresentPending = false;
pipeline->output()->presentFailed();
}
} }
for (const auto &obj : unusedObjects) { for (const auto &obj : unusedObjects) {
printProps(obj, PrintMode::OnlyChanged); printProps(obj, PrintMode::OnlyChanged);
@ -187,7 +183,6 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
} }
} }
if (mode != CommitMode::Test) { if (mode != CommitMode::Test) {
pipeline->m_modesetPresentPending = false;
pipeline->m_pageflipPending = true; pipeline->m_pageflipPending = true;
pipeline->m_connector->commit(); pipeline->m_connector->commit();
if (pipeline->pending.crtc) { if (pipeline->pending.crtc) {
@ -225,9 +220,6 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
for (const auto &pipeline : pipelines) { for (const auto &pipeline : pipelines) {
pipeline->revertPendingChanges(); pipeline->revertPendingChanges();
pipeline->applyPendingChangesLegacy(); pipeline->applyPendingChangesLegacy();
if (mode == CommitMode::CommitModeset && pipeline->output() && pipeline->activePending()) {
pipeline->output()->presentFailed();
}
} }
return false; return false;
} else { } else {
@ -510,6 +502,11 @@ bool DrmPipeline::modesetPresentPending() const
return m_modesetPresentPending; return m_modesetPresentPending;
} }
void DrmPipeline::resetModesetPresentPending()
{
m_modesetPresentPending = false;
}
DrmCrtc *DrmPipeline::currentCrtc() const DrmCrtc *DrmPipeline::currentCrtc() const
{ {
return m_current.crtc; return m_current.crtc;

View file

@ -80,6 +80,7 @@ public:
void pageFlipped(std::chrono::nanoseconds timestamp); void pageFlipped(std::chrono::nanoseconds timestamp);
bool pageflipPending() const; bool pageflipPending() const;
bool modesetPresentPending() const; bool modesetPresentPending() const;
void resetModesetPresentPending();
void printDebugInfo() const; void printDebugInfo() const;
QSize sourceSize() const; QSize sourceSize() const;