platforms/drm: keep disconnected DrmConnectors around

This commit is contained in:
Xaver Hugl 2021-10-27 21:56:39 +02:00
parent a07aae8282
commit 102fb3d5f2
3 changed files with 87 additions and 93 deletions

View file

@ -255,40 +255,24 @@ bool DrmGpu::updateOutputs()
for (int i = 0; i < resources->count_connectors; ++i) {
const uint32_t currentConnector = resources->connectors[i];
auto it = std::find_if(m_connectors.constBegin(), m_connectors.constEnd(), [currentConnector] (DrmConnector *c) { return c->id() == currentConnector; });
if (it == m_connectors.constEnd()) {
auto c = new DrmConnector(this, currentConnector);
if (!c->init() || !c->isConnected()) {
delete c;
DrmConnector *conn = it == m_connectors.constEnd() ? nullptr : *it;
if (!conn) {
conn = new DrmConnector(this, currentConnector);
if (!conn->init()) {
delete conn;
continue;
}
m_connectors << c;
m_pipelines << c->pipeline();
m_connectors << conn;
} else {
(*it)->updateProperties();
if ((*it)->isConnected()) {
removedConnectors.removeOne(*it);
removedConnectors.removeOne(conn);
conn->updateProperties();
}
}
}
for (const auto &connector : qAsConst(removedConnectors)) {
if (auto output = findOutput(connector->id())) {
removeOutput(output);
} else if (auto leaseOutput = findLeaseOutput(connector->id())) {
removeLeaseOutput(leaseOutput);
}
m_connectors.removeOne(connector);
m_pipelines.removeOne(connector->pipeline());
delete connector;
}
// find unused and connected connectors
for (const auto &conn : qAsConst(m_connectors)) {
auto output = findOutput(conn->id());
if (conn->isConnected()) {
if (output) {
if (auto output = findOutput(conn->id())) {
output->updateModes();
} else if (!findLeaseOutput(conn->id())) {
qCDebug(KWIN_DRM, "New %soutput on GPU %s: %s", conn->isNonDesktop() ? "non-desktop " : "", qPrintable(m_devNode), qPrintable(conn->modelName()));
m_pipelines << conn->pipeline();
if (conn->isNonDesktop()) {
auto leaseOutput = new DrmLeaseOutput(conn->pipeline(), m_leaseDevice);
m_leaseOutputs << leaseOutput;
@ -302,12 +286,21 @@ bool DrmGpu::updateOutputs()
Q_EMIT outputAdded(output);
}
}
} else if (output) {
} else if (auto output = findOutput(conn->id())) {
removeOutput(output);
} else if (const auto leaseOutput = findLeaseOutput(conn->id())) {
} else if (auto leaseOutput = findLeaseOutput(conn->id())) {
removeLeaseOutput(leaseOutput);
}
}
for (const auto &connector : qAsConst(removedConnectors)) {
if (auto output = findOutput(connector->id())) {
removeOutput(output);
} else if (auto leaseOutput = findLeaseOutput(connector->id())) {
removeLeaseOutput(leaseOutput);
}
m_connectors.removeOne(connector);
delete connector;
}
// update crtc properties
for (const auto &crtc : qAsConst(m_crtcs)) {
@ -545,6 +538,7 @@ void DrmGpu::removeOutput(DrmOutput *output)
{
qCDebug(KWIN_DRM) << "Removing output" << output;
m_drmOutputs.removeOne(output);
m_pipelines.removeOne(output->pipeline());
m_outputs.removeOne(output);
Q_EMIT outputRemoved(output);
delete output;
@ -666,6 +660,7 @@ void DrmGpu::removeLeaseOutput(DrmLeaseOutput *output)
{
qCDebug(KWIN_DRM) << "Removing leased output" << output;
m_leaseOutputs.removeOne(output);
m_pipelines.removeOne(output->pipeline());
delete output;
}

View file

@ -78,66 +78,7 @@ quint64 refreshRateForMode(_drmModeModeInfo *m)
bool DrmConnector::init()
{
if (!m_conn || !m_conn->count_modes) {
return false;
}
if (!initProps()) {
return false;
}
if (const auto &dpms = getProp(PropertyIndex::Dpms)) {
dpms->setLegacy();
}
auto underscan = m_props[static_cast<uint32_t>(PropertyIndex::Underscan)];
auto vborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_vborder)];
auto hborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_hborder)];
if (underscan && vborder && hborder) {
underscan->setEnum(vborder->current() > 0 ? UnderscanOptions::On : UnderscanOptions::Off);
} else {
deleteProp(PropertyIndex::Underscan);
deleteProp(PropertyIndex::Underscan_vborder);
deleteProp(PropertyIndex::Underscan_hborder);
}
// parse edid
auto edidProp = getProp(PropertyIndex::Edid);
if (edidProp) {
DrmScopedPointer<drmModePropertyBlobRes> blob(drmModeGetPropertyBlob(gpu()->fd(), edidProp->current()));
if (blob && blob->data) {
m_edid = Edid(blob->data, blob->length);
if (!m_edid.isValid()) {
qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this;
}
}
deleteProp(PropertyIndex::Edid);
} else {
qCDebug(KWIN_DRM) << "Could not find edid for connector" << this;
}
// check the physical size
if (m_edid.physicalSize().isEmpty()) {
m_physicalSize = QSize(m_conn->mmWidth, m_conn->mmHeight);
} else {
m_physicalSize = m_edid.physicalSize();
}
// the size might be completely borked. E.g. Samsung SyncMaster 2494HS reports 160x90 while in truth it's 520x292
// as this information is used to calculate DPI info, it's going to result in everything being huge
const QByteArray unknown = QByteArrayLiteral("unknown");
KConfigGroup group = kwinApp()->config()->group("EdidOverwrite").group(m_edid.eisaId().isEmpty() ? unknown : m_edid.eisaId())
.group(m_edid.monitorName().isEmpty() ? unknown : m_edid.monitorName())
.group(m_edid.serialNumber().isEmpty() ? unknown : m_edid.serialNumber());
if (group.hasKey("PhysicalSize")) {
const QSize overwriteSize = group.readEntry("PhysicalSize", m_physicalSize);
qCWarning(KWIN_DRM) << "Overwriting monitor physical size for" << m_edid.eisaId() << "/" << m_edid.monitorName() << "/" << m_edid.serialNumber() << " from " << m_physicalSize << "to " << overwriteSize;
m_physicalSize = overwriteSize;
}
// init modes
updateModes();
return true;
return m_conn && initProps();
}
bool DrmConnector::isConnected() const
@ -349,7 +290,62 @@ bool DrmConnector::updateProperties()
return false;
}
m_conn.reset(drmModeGetConnector(gpu()->fd(), id()));
return m_conn != nullptr;
if (!m_conn) {
return false;
}
if (const auto &dpms = getProp(PropertyIndex::Dpms)) {
dpms->setLegacy();
}
auto underscan = m_props[static_cast<uint32_t>(PropertyIndex::Underscan)];
auto vborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_vborder)];
auto hborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_hborder)];
if (underscan && vborder && hborder) {
underscan->setEnum(vborder->current() > 0 ? UnderscanOptions::On : UnderscanOptions::Off);
} else {
deleteProp(PropertyIndex::Underscan);
deleteProp(PropertyIndex::Underscan_vborder);
deleteProp(PropertyIndex::Underscan_hborder);
}
// parse edid
auto edidProp = getProp(PropertyIndex::Edid);
if (edidProp) {
DrmScopedPointer<drmModePropertyBlobRes> blob(drmModeGetPropertyBlob(gpu()->fd(), edidProp->current()));
if (blob && blob->data) {
m_edid = Edid(blob->data, blob->length);
if (!m_edid.isValid()) {
qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this;
}
}
deleteProp(PropertyIndex::Edid);
} else {
qCDebug(KWIN_DRM) << "Could not find edid for connector" << this;
}
// check the physical size
if (m_edid.physicalSize().isEmpty()) {
m_physicalSize = QSize(m_conn->mmWidth, m_conn->mmHeight);
} else {
m_physicalSize = m_edid.physicalSize();
}
// the size might be completely borked. E.g. Samsung SyncMaster 2494HS reports 160x90 while in truth it's 520x292
// as this information is used to calculate DPI info, it's going to result in everything being huge
const QByteArray unknown = QByteArrayLiteral("unknown");
KConfigGroup group = kwinApp()->config()->group("EdidOverwrite").group(m_edid.eisaId().isEmpty() ? unknown : m_edid.eisaId())
.group(m_edid.monitorName().isEmpty() ? unknown : m_edid.monitorName())
.group(m_edid.serialNumber().isEmpty() ? unknown : m_edid.serialNumber());
if (group.hasKey("PhysicalSize")) {
const QSize overwriteSize = group.readEntry("PhysicalSize", m_physicalSize);
qCWarning(KWIN_DRM) << "Overwriting monitor physical size for" << m_edid.eisaId() << "/" << m_edid.monitorName() << "/" << m_edid.serialNumber() << " from " << m_physicalSize << "to " << overwriteSize;
m_physicalSize = overwriteSize;
}
// init modes
updateModes();
return true;
}
QVector<uint32_t> DrmConnector::encoders() const

View file

@ -80,7 +80,7 @@ bool DrmOutput::initCursor(const QSize &cursorSize)
bool DrmOutput::hideCursor()
{
if (!isEnabled()) {
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
bool visibleBefore = m_pipeline->isCursorVisible();
@ -97,7 +97,7 @@ bool DrmOutput::hideCursor()
bool DrmOutput::showCursor()
{
if (!isEnabled()) {
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
bool visibleBefore = m_pipeline->isCursorVisible();
@ -126,7 +126,7 @@ static bool isCursorSpriteCompatible(const QImage *buffer, const QImage *sprite)
bool DrmOutput::updateCursor()
{
if (!isEnabled()) {
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
const Cursor *cursor = Cursors::self()->currentCursor();
@ -164,7 +164,7 @@ bool DrmOutput::updateCursor()
bool DrmOutput::moveCursor()
{
if (!isEnabled()) {
if (!isEnabled() || !m_connector->isConnected()) {
return true;
}
Cursor *cursor = Cursors::self()->currentCursor();
@ -457,6 +457,9 @@ bool DrmOutput::queueChanges(const WaylandOutputConfig &config)
void DrmOutput::applyQueuedChanges(const WaylandOutputConfig &config)
{
if (!m_connector->isConnected()) {
return;
}
Q_EMIT aboutToChange();
m_pipeline->applyPendingChanges();