outputconfigurationstore: differentiate between outputs with their mst path
The DisplayPort multi stream path should be more stable in comparison to connector names, so prefer that for differentiating between outputs with the same EDID. BUG: 470718
This commit is contained in:
parent
0391b65628
commit
7db4df9915
7 changed files with 73 additions and 4 deletions
|
@ -136,6 +136,7 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
|
|||
QByteArrayLiteral("BT2020_RGB"),
|
||||
QByteArrayLiteral("BT2020_YCC"),
|
||||
})
|
||||
, path(this, QByteArrayLiteral("PATH"))
|
||||
, m_conn(drmModeGetConnector(gpu->fd(), connectorId))
|
||||
, m_pipeline(m_conn ? std::make_unique<DrmPipeline>(this) : nullptr)
|
||||
{
|
||||
|
@ -187,6 +188,11 @@ QSize DrmConnector::physicalSize() const
|
|||
return m_physicalSize;
|
||||
}
|
||||
|
||||
QByteArray DrmConnector::mstPath() const
|
||||
{
|
||||
return m_mstPath;
|
||||
}
|
||||
|
||||
QList<std::shared_ptr<DrmConnectorMode>> DrmConnector::modes() const
|
||||
{
|
||||
return m_modes;
|
||||
|
@ -245,6 +251,7 @@ bool DrmConnector::updateProperties()
|
|||
hdrMetadata.update(props);
|
||||
scalingMode.update(props);
|
||||
colorspace.update(props);
|
||||
path.update(props);
|
||||
|
||||
if (gpu()->atomicModeSetting() && !crtcId.isValid()) {
|
||||
return false;
|
||||
|
@ -298,6 +305,23 @@ bool DrmConnector::updateProperties()
|
|||
}
|
||||
}
|
||||
|
||||
m_mstPath.clear();
|
||||
if (auto blob = path.immutableBlob()) {
|
||||
QByteArray value = QByteArray(static_cast<const char *>(blob->data), blob->length);
|
||||
if (value.startsWith("mst:")) {
|
||||
// for backwards compatibility reasons the string also contains the drm connector id
|
||||
// remove that to get a more stable identifier
|
||||
const ssize_t firstHyphen = value.indexOf('-');
|
||||
if (firstHyphen > 0) {
|
||||
m_mstPath = value.mid(firstHyphen);
|
||||
} else {
|
||||
qCWarning(KWIN_DRM) << "Unexpected format in path property:" << value;
|
||||
}
|
||||
} else {
|
||||
qCWarning(KWIN_DRM) << "Unknown path type detected:" << value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,10 @@ public:
|
|||
QString connectorName() const;
|
||||
QString modelName() const;
|
||||
QSize physicalSize() const;
|
||||
/**
|
||||
* @returns the mst path of the connector. Is empty if invalid
|
||||
*/
|
||||
QByteArray mstPath() const;
|
||||
|
||||
QList<std::shared_ptr<DrmConnectorMode>> modes() const;
|
||||
std::shared_ptr<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const;
|
||||
|
@ -128,6 +132,7 @@ public:
|
|||
DrmProperty hdrMetadata;
|
||||
DrmEnumProperty<ScalingMode> scalingMode;
|
||||
DrmEnumProperty<Colorspace> colorspace;
|
||||
DrmProperty path;
|
||||
|
||||
static DrmContentType kwinToDrmContentType(ContentType type);
|
||||
static OutputTransform toKWinTransform(PanelOrientation orientation);
|
||||
|
@ -145,6 +150,7 @@ private:
|
|||
QList<std::shared_ptr<DrmConnectorMode>> m_driverModes;
|
||||
QList<std::shared_ptr<DrmConnectorMode>> m_modes;
|
||||
uint32_t m_possibleCrtcs = 0;
|
||||
QByteArray m_mstPath;
|
||||
|
||||
friend QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj);
|
||||
};
|
||||
|
|
|
@ -85,6 +85,7 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
|
|||
.panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : OutputTransform::Normal,
|
||||
.internal = conn->isInternal(),
|
||||
.nonDesktop = conn->isNonDesktop(),
|
||||
.mstPath = conn->mstPath(),
|
||||
});
|
||||
|
||||
initialState.modes = getModes();
|
||||
|
|
|
@ -579,6 +579,11 @@ QString Output::iccProfilePath() const
|
|||
return m_state.iccProfilePath;
|
||||
}
|
||||
|
||||
QByteArray Output::mstPath() const
|
||||
{
|
||||
return m_information.mstPath;
|
||||
}
|
||||
|
||||
bool Output::updateCursorLayer()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -317,6 +317,10 @@ public:
|
|||
AutoRotationPolicy autoRotationPolicy() const;
|
||||
std::shared_ptr<IccProfile> iccProfile() const;
|
||||
QString iccProfilePath() const;
|
||||
/**
|
||||
* @returns the mst path of this output. Is empty if invalid
|
||||
*/
|
||||
QByteArray mstPath() const;
|
||||
|
||||
virtual bool setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation);
|
||||
virtual bool setChannelFactors(const QVector3D &rgb);
|
||||
|
@ -399,6 +403,7 @@ protected:
|
|||
bool internal = false;
|
||||
bool placeholder = false;
|
||||
bool nonDesktop = false;
|
||||
QByteArray mstPath;
|
||||
};
|
||||
|
||||
struct State
|
||||
|
|
|
@ -128,12 +128,27 @@ std::optional<std::pair<OutputConfigurationStore::Setup *, std::unordered_map<Ou
|
|||
|
||||
std::optional<size_t> OutputConfigurationStore::findOutput(Output *output, const QList<Output *> &allOutputs) const
|
||||
{
|
||||
const bool hasDuplicate = std::any_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
|
||||
const bool duplicateEdid = std::any_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
|
||||
return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier();
|
||||
});
|
||||
const auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [hasDuplicate, output](const auto &outputState) {
|
||||
return outputState.edidIdentifier == output->edid().identifier()
|
||||
&& (!hasDuplicate || outputState.connectorName == output->name());
|
||||
const bool duplicateMst = std::any_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
|
||||
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(), [duplicateEdid, duplicateMst, output](const auto &outputState) {
|
||||
if (outputState.edidIdentifier != output->edid().identifier()) {
|
||||
return false;
|
||||
}
|
||||
if (!duplicateEdid) {
|
||||
return true;
|
||||
}
|
||||
if (!output->mstPath().isEmpty()) {
|
||||
if (outputState.mstPath != output->mstPath()) {
|
||||
return false;
|
||||
} else if (!duplicateMst) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return outputState.connectorName == output->name();
|
||||
});
|
||||
if (it != m_outputs.end()) {
|
||||
return std::distance(m_outputs.begin(), it);
|
||||
|
@ -181,6 +196,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
|
|||
m_outputs[*outputIndex] = OutputState{
|
||||
.edidIdentifier = output->edid().identifier(),
|
||||
.connectorName = output->name(),
|
||||
.mstPath = output->mstPath(),
|
||||
.mode = ModeData{
|
||||
.size = mode->size(),
|
||||
.refreshRate = mode->refreshRate(),
|
||||
|
@ -208,6 +224,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
|
|||
m_outputs[*outputIndex] = OutputState{
|
||||
.edidIdentifier = output->edid().identifier(),
|
||||
.connectorName = output->name(),
|
||||
.mstPath = output->mstPath(),
|
||||
.mode = ModeData{
|
||||
.size = mode->size(),
|
||||
.refreshRate = mode->refreshRate(),
|
||||
|
@ -528,6 +545,12 @@ void OutputConfigurationStore::load()
|
|||
hasIdentifier = true;
|
||||
}
|
||||
}
|
||||
if (const auto it = data.find("mstPath"); it != data.end()) {
|
||||
if (const auto str = it->toString(); !str.isEmpty()) {
|
||||
state.mstPath = str;
|
||||
hasIdentifier = true;
|
||||
}
|
||||
}
|
||||
if (!hasIdentifier) {
|
||||
// without an identifier the settings are useless
|
||||
// we still have to push something into the list so that the indices stay correct
|
||||
|
@ -740,6 +763,9 @@ void OutputConfigurationStore::save()
|
|||
if (output.connectorName) {
|
||||
o["connectorName"] = *output.connectorName;
|
||||
}
|
||||
if (!output.mstPath.isEmpty()) {
|
||||
o["mstPath"] = output.mstPath;
|
||||
}
|
||||
if (output.mode) {
|
||||
QJsonObject mode;
|
||||
mode["width"] = output.mode->size.width();
|
||||
|
|
|
@ -61,6 +61,8 @@ private:
|
|||
// identification data
|
||||
std::optional<QString> edidIdentifier;
|
||||
std::optional<QString> connectorName;
|
||||
// empty if invalid
|
||||
QString mstPath;
|
||||
// actual state
|
||||
std::optional<ModeData> mode;
|
||||
std::optional<double> scale;
|
||||
|
|
Loading…
Reference in a new issue