backends/drm: handle disconnected but not removed connector objects properly

The kernel doesn't disable connector objects that represent physical ports
when the output gets removed. If KWin tries to change the output configuration
without explicitly disabling the connector, atomic commits can fail.
This commit is contained in:
Xaver Hugl 2022-07-09 04:25:24 +02:00
parent e96b9ba499
commit 2d43f3eee2

View file

@ -260,32 +260,43 @@ bool DrmGpu::updateOutputs()
DrmConnector *conn = it == m_connectors.constEnd() ? nullptr : *it;
if (!conn) {
conn = new DrmConnector(this, currentConnector);
if (!conn->init() || !conn->isConnected()) {
if (!conn->init()) {
delete conn;
continue;
}
m_connectors << conn;
m_allObjects << conn;
qCDebug(KWIN_DRM, "New %soutput on GPU %s: %s", conn->isNonDesktop() ? "non-desktop " : "", qPrintable(m_devNode), qPrintable(conn->modelName()));
const auto pipeline = conn->pipeline();
m_pipelines << pipeline;
if (conn->isNonDesktop()) {
auto leaseOutput = new DrmLeaseOutput(pipeline, m_leaseDevice);
m_leaseOutputs << leaseOutput;
} else {
auto output = new DrmOutput(pipeline);
m_drmOutputs << output;
m_outputs << output;
addedOutputs << output;
Q_EMIT outputAdded(output);
}
pipeline->setLayers(m_platform->renderBackend()->createPrimaryLayer(pipeline), m_platform->renderBackend()->createCursorLayer(pipeline));
pipeline->setActive(!conn->isNonDesktop());
pipeline->applyPendingChanges();
} else {
conn->updateProperties();
if (conn->isConnected()) {
removedConnectors.removeOne(conn);
removedConnectors.removeOne(conn);
}
auto output = findOutput(conn->id());
auto leaseOutput = findLeaseOutput(conn->id());
if (conn->isConnected()) {
if (!output && !leaseOutput) {
qCDebug(KWIN_DRM, "New %soutput on GPU %s: %s", conn->isNonDesktop() ? "non-desktop " : "", qPrintable(m_devNode), qPrintable(conn->modelName()));
const auto pipeline = conn->pipeline();
m_pipelines << pipeline;
if (conn->isNonDesktop()) {
auto leaseOutput = new DrmLeaseOutput(pipeline, m_leaseDevice);
m_leaseOutputs << leaseOutput;
} else {
auto output = new DrmOutput(pipeline);
m_drmOutputs << output;
m_outputs << output;
addedOutputs << output;
Q_EMIT outputAdded(output);
}
pipeline->setLayers(m_platform->renderBackend()->createPrimaryLayer(pipeline), m_platform->renderBackend()->createCursorLayer(pipeline));
pipeline->setActive(!conn->isNonDesktop());
pipeline->applyPendingChanges();
}
} else {
conn->disable();
if (output) {
removeOutput(output);
} else if (leaseOutput) {
removeLeaseOutput(leaseOutput);
}
}
}