outputconfigurationstore: add a fallback for when edid parsing fails

When edid parsing fails, KWin will base output settings on the connector, which
isn't great on its own, but at least works in many cases. When the edid can be
parsed later though, the display settings will reset because now the edid identifier
is used to exclude the old config (in which the latter is missing).
To work around that, this commit adds output identification based on the edid hash,
which is also not ideal, but can be safely matched with in case no output config
with a matching edid identifier exists.
This commit is contained in:
Xaver Hugl 2024-01-22 23:10:30 +01:00
parent 3cafc20981
commit 7e095412aa
2 changed files with 30 additions and 1 deletions

View file

@ -133,10 +133,13 @@ std::optional<size_t> OutputConfigurationStore::findOutput(Output *output, const
const bool uniqueEdid = !output->edid().identifier().isEmpty() && std::none_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) { const bool uniqueEdid = !output->edid().identifier().isEmpty() && std::none_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier(); return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier();
}); });
const bool uniqueEdidHash = !output->edid().hash().isEmpty() && std::none_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
return otherOutput != output && otherOutput->edid().hash() == output->edid().hash();
});
const bool uniqueMst = !output->mstPath().isEmpty() && std::none_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) { const bool uniqueMst = !output->mstPath().isEmpty() && std::none_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier() && otherOutput->mstPath() == output->mstPath(); return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier() && otherOutput->mstPath() == output->mstPath();
}); });
const auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [uniqueEdid, uniqueMst, output](const auto &outputState) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [&](const auto &outputState) {
if (output->edid().isValid()) { if (output->edid().isValid()) {
if (outputState.edidIdentifier != output->edid().identifier()) { if (outputState.edidIdentifier != output->edid().identifier()) {
return false; return false;
@ -144,6 +147,13 @@ std::optional<size_t> OutputConfigurationStore::findOutput(Output *output, const
return true; return true;
} }
} }
if (!output->edid().hash().isEmpty()) {
if (outputState.edidHash != output->edid().hash()) {
return false;
} else if (uniqueEdidHash) {
return true;
}
}
if (outputState.mstPath != output->mstPath()) { if (outputState.mstPath != output->mstPath()) {
return false; return false;
} else if (uniqueMst) { } else if (uniqueMst) {
@ -151,6 +161,12 @@ std::optional<size_t> OutputConfigurationStore::findOutput(Output *output, const
} }
return outputState.connectorName == output->name(); return outputState.connectorName == output->name();
}); });
if (it == m_outputs.end() && uniqueEdidHash) {
// handle the edge case of EDID parsing failing in the past but not failing anymore
it = std::find_if(m_outputs.begin(), m_outputs.end(), [&](const auto &outputState) {
return outputState.edidHash == output->edid().hash();
});
}
if (it != m_outputs.end()) { if (it != m_outputs.end()) {
return std::distance(m_outputs.begin(), it); return std::distance(m_outputs.begin(), it);
} else { } else {
@ -197,6 +213,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
m_outputs[*outputIndex] = OutputState{ m_outputs[*outputIndex] = OutputState{
.edidIdentifier = output->edid().identifier(), .edidIdentifier = output->edid().identifier(),
.connectorName = output->name(), .connectorName = output->name(),
.edidHash = output->edid().isValid() ? output->edid().hash() : QString{},
.mstPath = output->mstPath(), .mstPath = output->mstPath(),
.mode = ModeData{ .mode = ModeData{
.size = mode->size(), .size = mode->size(),
@ -229,6 +246,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
m_outputs[*outputIndex] = OutputState{ m_outputs[*outputIndex] = OutputState{
.edidIdentifier = output->edid().identifier(), .edidIdentifier = output->edid().identifier(),
.connectorName = output->name(), .connectorName = output->name(),
.edidHash = output->edid().isValid() ? output->edid().hash() : QString{},
.mstPath = output->mstPath(), .mstPath = output->mstPath(),
.mode = ModeData{ .mode = ModeData{
.size = mode->size(), .size = mode->size(),
@ -554,6 +572,12 @@ void OutputConfigurationStore::load()
hasIdentifier = true; hasIdentifier = true;
} }
} }
if (const auto it = data.find("edidHash"); it != data.end()) {
if (const auto str = it->toString(); !str.isEmpty()) {
state.edidHash = str;
hasIdentifier = true;
}
}
if (const auto it = data.find("connectorName"); it != data.end()) { if (const auto it = data.find("connectorName"); it != data.end()) {
if (const auto str = it->toString(); !str.isEmpty()) { if (const auto str = it->toString(); !str.isEmpty()) {
state.connectorName = str; state.connectorName = str;
@ -576,6 +600,7 @@ void OutputConfigurationStore::load()
const bool hasDuplicate = std::any_of(outputDatas.begin(), outputDatas.end(), [&state](const auto &data) { const bool hasDuplicate = std::any_of(outputDatas.begin(), outputDatas.end(), [&state](const auto &data) {
return data return data
&& data->edidIdentifier == state.edidIdentifier && data->edidIdentifier == state.edidIdentifier
&& data->edidHash == state.edidHash
&& data->mstPath == state.mstPath && data->mstPath == state.mstPath
&& data->connectorName == state.connectorName; && data->connectorName == state.connectorName;
}); });
@ -808,6 +833,9 @@ void OutputConfigurationStore::save()
if (output.edidIdentifier) { if (output.edidIdentifier) {
o["edidIdentifier"] = *output.edidIdentifier; o["edidIdentifier"] = *output.edidIdentifier;
} }
if (!output.edidHash.isEmpty()) {
o["edidHash"] = output.edidHash;
}
if (output.connectorName) { if (output.connectorName) {
o["connectorName"] = *output.connectorName; o["connectorName"] = *output.connectorName;
} }

View file

@ -62,6 +62,7 @@ private:
std::optional<QString> edidIdentifier; std::optional<QString> edidIdentifier;
std::optional<QString> connectorName; std::optional<QString> connectorName;
// empty if invalid // empty if invalid
QString edidHash;
QString mstPath; QString mstPath;
// actual state // actual state
std::optional<ModeData> mode; std::optional<ModeData> mode;