backends/drm: test and apply all mode changes at once

This avoids doing multiple atomic tests with outdated state for when multiple
outputs change simultaneously, and avoids crashing because outputs get used
before they're fully constructed
(https://crash-reports.kde.org/organizations/kde/issues/40960)
This commit is contained in:
Xaver Hugl 2024-07-02 14:43:05 +02:00
parent 84e3ff88c3
commit b103decda2
3 changed files with 13 additions and 8 deletions

View file

@ -312,7 +312,19 @@ bool DrmGpu::updateOutputs()
}
}
// try to apply mode changes triggered above
DrmPipeline::Error err = testPendingConfiguration();
if (err == DrmPipeline::Error::None) {
for (const auto &pipeline : std::as_const(m_pipelines)) {
pipeline->applyPendingChanges();
}
} else {
for (const auto &pipeline : std::as_const(m_pipelines)) {
pipeline->revertPendingChanges();
}
// try again, with the mode changes reverted
err = testPendingConfiguration();
}
if (err == DrmPipeline::Error::None) {
for (const auto &pipeline : std::as_const(m_pipelines)) {
pipeline->applyPendingChanges();

View file

@ -217,13 +217,6 @@ void DrmOutput::updateConnectorProperties()
if (currentMode != m_pipeline->mode()) {
// DrmConnector::findCurrentMode might fail
m_pipeline->setMode(currentMode ? currentMode : m_pipeline->connector()->modes().constFirst());
if (m_gpu->testPendingConfiguration() == DrmPipeline::Error::None) {
m_pipeline->applyPendingChanges();
m_renderLoop->setRefreshRate(m_pipeline->mode()->refreshRate());
} else {
qCWarning(KWIN_DRM) << "Setting changed mode failed!";
m_pipeline->revertPendingChanges();
}
}
}
@ -231,7 +224,6 @@ void DrmOutput::updateConnectorProperties()
if (!next.currentMode) {
// some mode needs to be set
next.currentMode = next.modes.constFirst();
m_renderLoop->setRefreshRate(next.currentMode->refreshRate());
m_pipeline->setMode(std::static_pointer_cast<DrmConnectorMode>(next.currentMode));
m_pipeline->applyPendingChanges();
}

View file

@ -433,6 +433,7 @@ void DrmPipeline::applyPendingChanges()
m_commitThread->setModeInfo(m_pending.mode->refreshRate(), m_pending.mode->vblankTime());
if (m_output) {
m_output->renderLoop()->setPresentationSafetyMargin(m_commitThread->safetyMargin());
m_output->renderLoop()->setRefreshRate(m_pending.mode->refreshRate());
}
}