diff --git a/src/backends/drm/CMakeLists.txt b/src/backends/drm/CMakeLists.txt index 95fa76db7a..d2bb590f58 100644 --- a/src/backends/drm/CMakeLists.txt +++ b/src/backends/drm/CMakeLists.txt @@ -34,7 +34,7 @@ set(DRM_SOURCES add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) set_target_properties(KWinWaylandDrmBackend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.waylandbackends/") -target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm gbm::gbm) +target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm gbm::gbm PkgConfig::Libxcvt) install( TARGETS diff --git a/src/backends/drm/drm_object_connector.cpp b/src/backends/drm/drm_object_connector.cpp index 81a9cb2fbf..0bad84c99b 100644 --- a/src/backends/drm/drm_object_connector.cpp +++ b/src/backends/drm/drm_object_connector.cpp @@ -21,6 +21,7 @@ #include #include +#include namespace KWin { @@ -345,6 +346,7 @@ bool DrmConnector::updateProperties() if (m_modes.isEmpty()) { return false; } else { + generateCommonModes(); if (!m_pipeline->pending.mode) { m_pipeline->pending.mode = m_modes.constFirst(); m_pipeline->applyPendingChanges(); @@ -392,6 +394,73 @@ DrmConnector::LinkStatus DrmConnector::linkStatus() const return LinkStatus::Good; } +static const QVector s_commonModes = { + /* 4:3 (1.33) */ + QSize(1600, 1200), + QSize(1280, 1024), /* 5:4 (1.25) */ + QSize(1024, 768), + /* 16:10 (1.6) */ + QSize(2560, 1600), + QSize(1920, 1200), + QSize(1280, 800), + /* 16:9 (1.77) */ + QSize(5120, 2880), + QSize(3840, 2160), + QSize(3200, 1800), + QSize(2880, 1620), + QSize(2560, 1440), + QSize(1920, 1080), + QSize(1600, 900), + QSize(1368, 768), + QSize(1280, 720), +}; + +void DrmConnector::generateCommonModes() +{ + uint32_t maxBandwidthEstimation = 0; + QSize maxSize; + for (const auto &mode : qAsConst(m_modes)) { + if (mode->size().width() > maxSize.width() || mode->size().height() > maxSize.height()) { + maxSize = mode->size(); + maxBandwidthEstimation = std::max(maxBandwidthEstimation, static_cast(mode->size().width() * mode->size().height() * mode->refreshRate())); + } + } + for (const auto &size : s_commonModes) { + uint32_t bandwidthEstimation = size.width() * size.height() * 60000; + const auto it = std::find_if(m_modes.constBegin(), m_modes.constEnd(), [size](const auto &mode) { + return mode->size() == size; + }); + if (it == m_modes.constEnd() && size.width() <= maxSize.width() && size.height() <= maxSize.height() && bandwidthEstimation < maxBandwidthEstimation) { + generateMode(size, 60000); + } + } +} + +void DrmConnector::generateMode(const QSize &size, uint32_t refreshRate) +{ + auto modeInfo = libxcvt_gen_mode_info(size.width(), size.height(), refreshRate, false, false); + + drmModeModeInfo mode; + mode.vdisplay = modeInfo->vdisplay; + mode.hdisplay = modeInfo->hdisplay; + mode.clock = modeInfo->dot_clock; + mode.hsync_start = modeInfo->hsync_start; + mode.hsync_end = modeInfo->hsync_end; + mode.htotal = modeInfo->htotal; + mode.vsync_start = modeInfo->vsync_start; + mode.vsync_end = modeInfo->vsync_end; + mode.vtotal = modeInfo->vtotal; + mode.vrefresh = modeInfo->vrefresh; + mode.flags = modeInfo->mode_flags; + + mode.type = DRM_MODE_TYPE_USERDEF; + sprintf(mode.name, "%dx%d@%d", size.width(), size.height(), mode.vrefresh); + + m_modes << QSharedPointer::create(this, mode); + + free(modeInfo); +} + QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj) { QDebugStateSaver saver(s); diff --git a/src/backends/drm/drm_object_connector.h b/src/backends/drm/drm_object_connector.h index 2e4479a828..6cbca61dfb 100644 --- a/src/backends/drm/drm_object_connector.h +++ b/src/backends/drm/drm_object_connector.h @@ -105,6 +105,9 @@ public: LinkStatus linkStatus() const; private: + void generateCommonModes(); + void generateMode(const QSize &size, uint32_t refreshRate); + QScopedPointer m_pipeline; DrmScopedPointer m_conn; Edid m_edid;