diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index 2cdf43e42a..a86c9bc8e5 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -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; } diff --git a/src/backends/drm/drm_object_connector.cpp b/src/backends/drm/drm_object_connector.cpp index 47228013d6..20a02206a3 100644 --- a/src/backends/drm/drm_object_connector.cpp +++ b/src/backends/drm/drm_object_connector.cpp @@ -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(PropertyIndex::Underscan)]; - auto vborder = m_props[static_cast(PropertyIndex::Underscan_vborder)]; - auto hborder = m_props[static_cast(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 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(PropertyIndex::Underscan)]; + auto vborder = m_props[static_cast(PropertyIndex::Underscan_vborder)]; + auto hborder = m_props[static_cast(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 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 DrmConnector::encoders() const diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 57c92e8725..76bbb09631 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -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();