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
master
Xaver Hugl 11 months ago
parent 0391b65628
commit 7db4df9915

@ -136,6 +136,7 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
QByteArrayLiteral("BT2020_RGB"), QByteArrayLiteral("BT2020_RGB"),
QByteArrayLiteral("BT2020_YCC"), QByteArrayLiteral("BT2020_YCC"),
}) })
, path(this, QByteArrayLiteral("PATH"))
, m_conn(drmModeGetConnector(gpu->fd(), connectorId)) , m_conn(drmModeGetConnector(gpu->fd(), connectorId))
, m_pipeline(m_conn ? std::make_unique<DrmPipeline>(this) : nullptr) , m_pipeline(m_conn ? std::make_unique<DrmPipeline>(this) : nullptr)
{ {
@ -187,6 +188,11 @@ QSize DrmConnector::physicalSize() const
return m_physicalSize; return m_physicalSize;
} }
QByteArray DrmConnector::mstPath() const
{
return m_mstPath;
}
QList<std::shared_ptr<DrmConnectorMode>> DrmConnector::modes() const QList<std::shared_ptr<DrmConnectorMode>> DrmConnector::modes() const
{ {
return m_modes; return m_modes;
@ -245,6 +251,7 @@ bool DrmConnector::updateProperties()
hdrMetadata.update(props); hdrMetadata.update(props);
scalingMode.update(props); scalingMode.update(props);
colorspace.update(props); colorspace.update(props);
path.update(props);
if (gpu()->atomicModeSetting() && !crtcId.isValid()) { if (gpu()->atomicModeSetting() && !crtcId.isValid()) {
return false; 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; return true;
} }

@ -64,6 +64,10 @@ public:
QString connectorName() const; QString connectorName() const;
QString modelName() const; QString modelName() const;
QSize physicalSize() 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; QList<std::shared_ptr<DrmConnectorMode>> modes() const;
std::shared_ptr<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const; std::shared_ptr<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const;
@ -128,6 +132,7 @@ public:
DrmProperty hdrMetadata; DrmProperty hdrMetadata;
DrmEnumProperty<ScalingMode> scalingMode; DrmEnumProperty<ScalingMode> scalingMode;
DrmEnumProperty<Colorspace> colorspace; DrmEnumProperty<Colorspace> colorspace;
DrmProperty path;
static DrmContentType kwinToDrmContentType(ContentType type); static DrmContentType kwinToDrmContentType(ContentType type);
static OutputTransform toKWinTransform(PanelOrientation orientation); static OutputTransform toKWinTransform(PanelOrientation orientation);
@ -145,6 +150,7 @@ private:
QList<std::shared_ptr<DrmConnectorMode>> m_driverModes; QList<std::shared_ptr<DrmConnectorMode>> m_driverModes;
QList<std::shared_ptr<DrmConnectorMode>> m_modes; QList<std::shared_ptr<DrmConnectorMode>> m_modes;
uint32_t m_possibleCrtcs = 0; uint32_t m_possibleCrtcs = 0;
QByteArray m_mstPath;
friend QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj); 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, .panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : OutputTransform::Normal,
.internal = conn->isInternal(), .internal = conn->isInternal(),
.nonDesktop = conn->isNonDesktop(), .nonDesktop = conn->isNonDesktop(),
.mstPath = conn->mstPath(),
}); });
initialState.modes = getModes(); initialState.modes = getModes();

@ -579,6 +579,11 @@ QString Output::iccProfilePath() const
return m_state.iccProfilePath; return m_state.iccProfilePath;
} }
QByteArray Output::mstPath() const
{
return m_information.mstPath;
}
bool Output::updateCursorLayer() bool Output::updateCursorLayer()
{ {
return false; return false;

@ -317,6 +317,10 @@ public:
AutoRotationPolicy autoRotationPolicy() const; AutoRotationPolicy autoRotationPolicy() const;
std::shared_ptr<IccProfile> iccProfile() const; std::shared_ptr<IccProfile> iccProfile() const;
QString iccProfilePath() 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 setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation);
virtual bool setChannelFactors(const QVector3D &rgb); virtual bool setChannelFactors(const QVector3D &rgb);
@ -399,6 +403,7 @@ protected:
bool internal = false; bool internal = false;
bool placeholder = false; bool placeholder = false;
bool nonDesktop = false; bool nonDesktop = false;
QByteArray mstPath;
}; };
struct State 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 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(); 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) { const bool duplicateMst = std::any_of(allOutputs.begin(), allOutputs.end(), [output](Output *otherOutput) {
return outputState.edidIdentifier == output->edid().identifier() return otherOutput != output && otherOutput->edid().identifier() == output->edid().identifier() && otherOutput->mstPath() == output->mstPath();
&& (!hasDuplicate || outputState.connectorName == output->name()); });
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()) { if (it != m_outputs.end()) {
return std::distance(m_outputs.begin(), it); return std::distance(m_outputs.begin(), it);
@ -181,6 +196,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(),
.mstPath = output->mstPath(),
.mode = ModeData{ .mode = ModeData{
.size = mode->size(), .size = mode->size(),
.refreshRate = mode->refreshRate(), .refreshRate = mode->refreshRate(),
@ -208,6 +224,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(),
.mstPath = output->mstPath(),
.mode = ModeData{ .mode = ModeData{
.size = mode->size(), .size = mode->size(),
.refreshRate = mode->refreshRate(), .refreshRate = mode->refreshRate(),
@ -528,6 +545,12 @@ void OutputConfigurationStore::load()
hasIdentifier = true; 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) { if (!hasIdentifier) {
// without an identifier the settings are useless // without an identifier the settings are useless
// we still have to push something into the list so that the indices stay correct // 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) { if (output.connectorName) {
o["connectorName"] = *output.connectorName; o["connectorName"] = *output.connectorName;
} }
if (!output.mstPath.isEmpty()) {
o["mstPath"] = output.mstPath;
}
if (output.mode) { if (output.mode) {
QJsonObject mode; QJsonObject mode;
mode["width"] = output.mode->size.width(); mode["width"] = output.mode->size.width();

@ -61,6 +61,8 @@ private:
// identification data // identification data
std::optional<QString> edidIdentifier; std::optional<QString> edidIdentifier;
std::optional<QString> connectorName; std::optional<QString> connectorName;
// empty if invalid
QString mstPath;
// actual state // actual state
std::optional<ModeData> mode; std::optional<ModeData> mode;
std::optional<double> scale; std::optional<double> scale;

Loading…
Cancel
Save