diff --git a/src/backends/drm/drm_object_connector.cpp b/src/backends/drm/drm_object_connector.cpp index 299a29620e..81a9cb2fbf 100644 --- a/src/backends/drm/drm_object_connector.cpp +++ b/src/backends/drm/drm_object_connector.cpp @@ -30,6 +30,11 @@ static bool checkIfEqual(const drmModeModeInfo *one, const drmModeModeInfo *two) return std::memcmp(one, two, sizeof(drmModeModeInfo)) == 0; } +static QSize resolutionForMode(const drmModeModeInfo *info) +{ + return QSize(info->hdisplay, info->vdisplay); +} + static quint64 refreshRateForMode(_drmModeModeInfo *m) { // Calculate higher precision (mHz) refresh rate @@ -47,11 +52,19 @@ static quint64 refreshRateForMode(_drmModeModeInfo *m) return refreshRate; } +static OutputMode::Flags flagsForMode(const drmModeModeInfo *info) +{ + OutputMode::Flags flags; + if (info->type & DRM_MODE_TYPE_PREFERRED) { + flags |= OutputMode::Flag::Preferred; + } + return flags; +} + DrmConnectorMode::DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode) - : m_connector(connector) + : OutputMode(resolutionForMode(&nativeMode), refreshRateForMode(&nativeMode), flagsForMode(&nativeMode)) + , m_connector(connector) , m_nativeMode(nativeMode) - , m_size(nativeMode.hdisplay, nativeMode.vdisplay) - , m_refreshRate(refreshRateForMode(&nativeMode)) { } @@ -68,16 +81,6 @@ drmModeModeInfo *DrmConnectorMode::nativeMode() return &m_nativeMode; } -QSize DrmConnectorMode::size() const -{ - return m_size; -} - -uint32_t DrmConnectorMode::refreshRate() const -{ - return m_refreshRate; -} - uint32_t DrmConnectorMode::blobId() { if (!m_blobId) { @@ -194,7 +197,7 @@ QSize DrmConnector::physicalSize() const return m_physicalSize; } -QVector> DrmConnector::modes() const +QList> DrmConnector::modes() const { return m_modes; } diff --git a/src/backends/drm/drm_object_connector.h b/src/backends/drm/drm_object_connector.h index 01c4eacdad..2e4479a828 100644 --- a/src/backends/drm/drm_object_connector.h +++ b/src/backends/drm/drm_object_connector.h @@ -29,25 +29,20 @@ class DrmCrtc; /** * The DrmConnectorMode class represents a native mode and the associated blob. */ -class DrmConnectorMode +class DrmConnectorMode : public OutputMode { public: DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode); - ~DrmConnectorMode(); + ~DrmConnectorMode() override; uint32_t blobId(); - drmModeModeInfo *nativeMode(); - QSize size() const; - uint32_t refreshRate() const; bool operator==(const DrmConnectorMode &otherMode); private: DrmConnector *m_connector; drmModeModeInfo m_nativeMode; - QSize m_size; - uint32_t m_refreshRate; uint32_t m_blobId = 0; }; @@ -98,7 +93,7 @@ public: QString modelName() const; QSize physicalSize() const; - QVector> modes() const; + QList> modes() const; QSharedPointer findMode(const drmModeModeInfo &modeInfo) const; Output::SubPixel subpixel() const; @@ -114,7 +109,7 @@ private: DrmScopedPointer m_conn; Edid m_edid; QSize m_physicalSize = QSize(-1, -1); - QVector> m_modes; + QList> m_modes; uint32_t m_possibleCrtcs = 0; friend QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj); diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 93859a9f46..5af27c1353 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -165,34 +165,16 @@ void DrmOutput::moveCursor() } } -QVector DrmOutput::getModes() const +QList> DrmOutput::getModes() const { - bool modeFound = false; - QVector modes; - const auto modelist = m_pipeline->connector()->modes(); + const auto drmModes = m_pipeline->connector()->modes(); - modes.reserve(modelist.count()); - for (int i = 0; i < modelist.count(); ++i) { - Mode mode; - // compare the actual mode objects, not the pointers! - if (*modelist[i] == *m_pipeline->pending.mode) { - mode.flags |= ModeFlag::Current; - modeFound = true; - } - if (modelist[i]->nativeMode()->type & DRM_MODE_TYPE_PREFERRED) { - mode.flags |= ModeFlag::Preferred; - } - - mode.id = i; - mode.size = modelist[i]->size(); - mode.refreshRate = modelist[i]->refreshRate(); - modes << mode; + QList> ret; + ret.reserve(drmModes.count()); + for (const QSharedPointer &drmMode : drmModes) { + ret.append(drmMode); } - if (!modeFound) { - // select first mode by default - modes[0].flags |= ModeFlag::Current; - } - return modes; + return ret; } void DrmOutput::initOutputDevice() @@ -201,7 +183,14 @@ void DrmOutput::initOutputDevice() setName(conn->connectorName()); initialize(conn->modelName(), conn->edid()->manufacturerString(), conn->edid()->eisaId(), conn->edid()->serialNumber(), - conn->physicalSize(), getModes(), conn->edid()->raw()); + conn->physicalSize(), conn->edid()->raw()); + + const QList> modes = getModes(); + QSharedPointer currentMode = m_pipeline->pending.mode; + if (!currentMode) { + currentMode = modes.constFirst(); + } + setModesInternal(modes, currentMode); } void DrmOutput::updateEnablement(bool enable) @@ -290,7 +279,8 @@ DrmPlane::Transformations outputToPlaneTransform(DrmOutput::Transform transform) void DrmOutput::updateModes() { - setModes(getModes()); + const QList> modes = getModes(); + if (m_pipeline->pending.crtc) { const auto currentMode = m_pipeline->connector()->findMode(m_pipeline->pending.crtc->queryCurrentMode()); if (currentMode != m_pipeline->pending.mode) { @@ -298,7 +288,6 @@ void DrmOutput::updateModes() m_pipeline->pending.mode = currentMode ? currentMode : m_pipeline->connector()->modes().constFirst(); if (m_gpu->testPendingConfiguration()) { m_pipeline->applyPendingChanges(); - setCurrentModeInternal(m_pipeline->pending.mode->size(), m_pipeline->pending.mode->refreshRate()); m_renderLoop->setRefreshRate(m_pipeline->pending.mode->refreshRate()); } else { qCWarning(KWIN_DRM) << "Setting changed mode failed!"; @@ -306,6 +295,13 @@ void DrmOutput::updateModes() } } } + + QSharedPointer currentMode = m_pipeline->pending.mode; + if (!currentMode) { + currentMode = modes.constFirst(); + } + + setModesInternal(modes, currentMode); } bool DrmOutput::present() @@ -384,7 +380,7 @@ void DrmOutput::applyQueuedChanges(const OutputConfiguration &config) setTransformInternal(props->transform); const auto &mode = m_pipeline->pending.mode; - setCurrentModeInternal(mode->size(), mode->refreshRate()); + setCurrentModeInternal(mode); m_renderLoop->setRefreshRate(mode->refreshRate()); setOverscanInternal(m_pipeline->pending.overscan); setRgbRangeInternal(m_pipeline->pending.rgbRange); diff --git a/src/backends/drm/drm_output.h b/src/backends/drm/drm_output.h index cc3309f5a2..43891e6c07 100644 --- a/src/backends/drm/drm_output.h +++ b/src/backends/drm/drm_output.h @@ -66,7 +66,7 @@ private: bool setDrmDpmsMode(DpmsMode mode); void setDpmsMode(DpmsMode mode) override; - QVector getModes() const; + QList> getModes() const; void updateCursor(); void moveCursor(); diff --git a/src/backends/drm/drm_virtual_output.cpp b/src/backends/drm/drm_virtual_output.cpp index 1e677b3d76..b7356efc13 100644 --- a/src/backends/drm/drm_virtual_output.cpp +++ b/src/backends/drm/drm_virtual_output.cpp @@ -33,16 +33,16 @@ DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize connect(m_vsyncMonitor, &VsyncMonitor::vblankOccurred, this, &DrmVirtualOutput::vblank); setName("Virtual-" + name); - m_modeIndex = 0; - QVector modes = {{size, 60000, Output::ModeFlags(Output::ModeFlag::Current) | Output::ModeFlag::Preferred, 0}}; initialize(QLatin1String("model_") + name, QLatin1String("manufacturer_") + name, QLatin1String("eisa_") + name, QLatin1String("serial_") + name, - modes[m_modeIndex].size, - modes, + size, QByteArray("EDID_") + name.toUtf8()); - m_renderLoop->setRefreshRate(modes[m_modeIndex].refreshRate); + + auto mode = QSharedPointer::create(size, 60000, OutputMode::Flag::Preferred); + setModesInternal({mode}, mode); + m_renderLoop->setRefreshRate(mode->refreshRate()); recreateSurface(); } diff --git a/src/backends/drm/drm_virtual_output.h b/src/backends/drm/drm_virtual_output.h index b42092673a..ef28b3f648 100644 --- a/src/backends/drm/drm_virtual_output.h +++ b/src/backends/drm/drm_virtual_output.h @@ -40,7 +40,6 @@ private: QSharedPointer m_layer; bool m_pageFlipPending = true; - int m_modeIndex = 0; SoftwareVsyncMonitor *m_vsyncMonitor; }; diff --git a/src/backends/virtual/virtual_output.cpp b/src/backends/virtual/virtual_output.cpp index 0427358da6..a9630de184 100644 --- a/src/backends/virtual/virtual_output.cpp +++ b/src/backends/virtual/virtual_output.cpp @@ -48,22 +48,19 @@ void VirtualOutput::init(const QPoint &logicalPosition, const QSize &pixelSize) m_renderLoop->setRefreshRate(refreshRate); m_vsyncMonitor->setRefreshRate(refreshRate); - Mode mode; - mode.id = 0; - mode.size = pixelSize; - mode.flags = ModeFlag::Current; - mode.refreshRate = refreshRate; initialize(QByteArray("model_").append(QByteArray::number(m_identifier)), QByteArray("manufacturer_").append(QByteArray::number(m_identifier)), QByteArray("eisa_").append(QByteArray::number(m_identifier)), QByteArray("serial_").append(QByteArray::number(m_identifier)), - pixelSize, {mode}, QByteArray("EDID_").append(QByteArray::number(m_identifier))); + pixelSize, QByteArray("EDID_").append(QByteArray::number(m_identifier))); + setGeometry(QRect(logicalPosition, pixelSize)); } void VirtualOutput::setGeometry(const QRect &geo) { - // TODO: set mode to have updated pixelSize + auto mode = QSharedPointer::create(geo.size(), m_vsyncMonitor->refreshRate()); + setModesInternal({mode}, mode); moveTo(geo.topLeft()); } diff --git a/src/backends/wayland/wayland_output.cpp b/src/backends/wayland/wayland_output.cpp index e35dc5042a..f51e90dcba 100644 --- a/src/backends/wayland/wayland_output.cpp +++ b/src/backends/wayland/wayland_output.cpp @@ -61,32 +61,20 @@ void WaylandOutput::init(const QPoint &logicalPosition, const QSize &pixelSize) { m_renderLoop->setRefreshRate(s_refreshRate); - const Mode mode{ - .size = pixelSize, - .refreshRate = s_refreshRate, - .flags = ModeFlag::Current, - .id = 0, - }; + auto mode = QSharedPointer::create(pixelSize, s_refreshRate); + setModesInternal({mode}, mode); static uint i = 0; - initialize(QStringLiteral("model_%1").arg(i++), "manufacturer_TODO", "eisa_TODO", "serial_TODO", pixelSize, {mode}, {}); + initialize(QStringLiteral("model_%1").arg(i++), "manufacturer_TODO", "eisa_TODO", "serial_TODO", pixelSize, {}); moveTo(logicalPosition); - setCurrentModeInternal(mode.size, mode.refreshRate); setScale(backend()->initialOutputScale()); } void WaylandOutput::setGeometry(const QPoint &logicalPosition, const QSize &pixelSize) { - const Mode mode{ - .size = pixelSize, - .refreshRate = s_refreshRate, - .flags = ModeFlag::Current, - .id = 0, - }; - - setModes({mode}); - setCurrentModeInternal(mode.size, mode.refreshRate); + auto mode = QSharedPointer::create(pixelSize, s_refreshRate); + setModesInternal({mode}, mode); moveTo(logicalPosition); Q_EMIT m_backend->screensQueried(); diff --git a/src/backends/x11/standalone/x11_output.cpp b/src/backends/x11/standalone/x11_output.cpp index 968daf1fb0..2ab5020940 100644 --- a/src/backends/x11/standalone/x11_output.cpp +++ b/src/backends/x11/standalone/x11_output.cpp @@ -65,7 +65,8 @@ bool X11Output::usesSoftwareCursor() const void X11Output::setMode(const QSize &size, int refreshRate) { - setCurrentModeInternal(size, refreshRate); + auto mode = QSharedPointer::create(size, refreshRate); + setModesInternal({mode}, mode); } void X11Output::setPhysicalSize(const QSize &size) diff --git a/src/backends/x11/standalone/x11placeholderoutput.cpp b/src/backends/x11/standalone/x11placeholderoutput.cpp index 9d43318e25..e1c4361f5c 100644 --- a/src/backends/x11/standalone/x11placeholderoutput.cpp +++ b/src/backends/x11/standalone/x11placeholderoutput.cpp @@ -20,20 +20,16 @@ X11PlaceholderOutput::X11PlaceholderOutput(RenderLoop *loop, QObject *parent) pixelSize = QSize(screen->width_in_pixels, screen->height_in_pixels); } - const Mode mode{ - .size = pixelSize, - .refreshRate = 60000, - .flags = ModeFlag::Current, - .id = 0, - }; - const QByteArray model = QByteArrayLiteral("kwin"); const QByteArray manufacturer = QByteArrayLiteral("xorg"); const QByteArray eisaId; const QByteArray serial; - initialize(model, manufacturer, eisaId, serial, pixelSize, {mode}, QByteArray()); + initialize(model, manufacturer, eisaId, serial, pixelSize, QByteArray()); setName(QStringLiteral("Placeholder-0")); + + auto mode = QSharedPointer::create(pixelSize, 60000); + setModesInternal({mode}, mode); } RenderLoop *X11PlaceholderOutput::renderLoop() const diff --git a/src/backends/x11/windowed/x11windowed_output.cpp b/src/backends/x11/windowed/x11windowed_output.cpp index e39f11b5ed..8b5d57268f 100644 --- a/src/backends/x11/windowed/x11windowed_output.cpp +++ b/src/backends/x11/windowed/x11windowed_output.cpp @@ -64,16 +64,13 @@ void X11WindowedOutput::init(const QPoint &logicalPosition, const QSize &pixelSi m_renderLoop->setRefreshRate(refreshRate); m_vsyncMonitor->setRefreshRate(refreshRate); - Mode mode; - mode.id = 0; - mode.size = pixelSize; - mode.flags = ModeFlag::Current; - mode.refreshRate = refreshRate; + auto mode = QSharedPointer::create(pixelSize, refreshRate); + setModesInternal({mode}, mode); // Physicial size must be adjusted, such that QPA calculates correct sizes of // internal elements. const QSize physicalSize = pixelSize / 96.0 * 25.4 / m_backend->initialOutputScale(); - initialize("model_TODO", "manufacturer_TODO", "eisa_TODO", "serial_TODO", physicalSize, {mode}, {}); + initialize("model_TODO", "manufacturer_TODO", "eisa_TODO", "serial_TODO", physicalSize, {}); setGeometry(logicalPosition, pixelSize); setScale(m_backend->initialOutputScale()); diff --git a/src/output.cpp b/src/output.cpp index 664cef7990..1372aa1076 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -38,6 +38,28 @@ QDebug operator<<(QDebug debug, const Output *output) return debug; } +OutputMode::OutputMode(const QSize &size, int refreshRate, Flags flags) + : m_size(size) + , m_refreshRate(refreshRate) + , m_flags(flags) +{ +} + +QSize OutputMode::size() const +{ + return m_size; +} + +int OutputMode::refreshRate() const +{ + return m_refreshRate; +} + +OutputMode::Flags OutputMode::flags() const +{ + return m_flags; +} + Output::Output(QObject *parent) : QObject(parent) { @@ -157,7 +179,7 @@ QSize Output::physicalSize() const int Output::refreshRate() const { - return m_refreshRate; + return m_currentMode->refreshRate(); } void Output::moveTo(const QPoint &pos) @@ -170,12 +192,12 @@ void Output::moveTo(const QPoint &pos) QSize Output::modeSize() const { - return m_modeSize; + return m_currentMode->size(); } QSize Output::pixelSize() const { - return orientateSize(m_modeSize); + return orientateSize(m_currentMode->size()); } QByteArray Output::edid() const @@ -183,22 +205,30 @@ QByteArray Output::edid() const return m_edid; } -bool Output::Mode::operator==(const Mode &other) const -{ - return id == other.id && other.flags == flags && size == other.size && refreshRate == other.refreshRate; -} - -QVector Output::modes() const +QList> Output::modes() const { return m_modes; } -void Output::setModes(const QVector &modes) +QSharedPointer Output::currentMode() const { - if (m_modes != modes) { - m_modes = modes; + return m_currentMode; +} + +void Output::setModesInternal(const QList> &modes, const QSharedPointer ¤tMode) +{ + const auto oldModes = m_modes; + const auto oldCurrentMode = m_currentMode; + + m_modes = modes; + m_currentMode = currentMode; + + if (m_modes != oldModes) { Q_EMIT modesChanged(); } + if (m_currentMode != oldCurrentMode) { + Q_EMIT currentModeChanged(); + } } Output::SubPixel Output::subPixel() const @@ -245,17 +275,13 @@ QString Output::description() const return m_manufacturer + ' ' + m_model; } -void Output::setCurrentModeInternal(const QSize &size, int refreshRate) +void Output::setCurrentModeInternal(const QSharedPointer ¤tMode) { - const bool sizeChanged = m_modeSize != size; - if (sizeChanged || m_refreshRate != refreshRate) { - m_modeSize = size; - m_refreshRate = refreshRate; + if (m_currentMode != currentMode) { + m_currentMode = currentMode; Q_EMIT currentModeChanged(); - if (sizeChanged) { - Q_EMIT geometryChanged(); - } + Q_EMIT geometryChanged(); } } @@ -271,8 +297,7 @@ static QUuid generateOutputId(const QString &eisaId, const QString &model, void Output::initialize(const QString &model, const QString &manufacturer, const QString &eisaId, const QString &serialNumber, - const QSize &physicalSize, - const QVector &modes, const QByteArray &edid) + const QSize &physicalSize, const QByteArray &edid) { m_serialNumber = serialNumber; m_eisaId = eisaId; @@ -280,16 +305,7 @@ void Output::initialize(const QString &model, const QString &manufacturer, m_model = model; m_physicalSize = physicalSize; m_edid = edid; - m_modes = modes; m_uuid = generateOutputId(m_eisaId, m_model, m_serialNumber, m_name); - - for (const Mode &mode : modes) { - if (mode.flags & ModeFlag::Current) { - m_modeSize = mode.size; - m_refreshRate = mode.refreshRate; - break; - } - } } QSize Output::orientateSize(const QSize &size) const diff --git a/src/output.h b/src/output.h index 8f11acec0f..afad24a3b2 100644 --- a/src/output.h +++ b/src/output.h @@ -29,6 +29,27 @@ class RenderLoop; class OutputConfiguration; class ColorTransformation; +class KWIN_EXPORT OutputMode +{ +public: + enum class Flag : uint { + Preferred = 0x1, + }; + Q_DECLARE_FLAGS(Flags, Flag) + + OutputMode(const QSize &size, int refreshRate, Flags flags = {}); + virtual ~OutputMode() = default; + + QSize size() const; + int refreshRate() const; + Flags flags() const; + +private: + const QSize m_size; + const int m_refreshRate; + const Flags m_flags; +}; + /** * Generic output representation. */ @@ -37,23 +58,6 @@ class KWIN_EXPORT Output : public QObject Q_OBJECT public: - enum class ModeFlag : uint { - Current = 0x1, - Preferred = 0x2, - }; - Q_DECLARE_FLAGS(ModeFlags, ModeFlag) - Q_ENUM(ModeFlag) - - struct Mode - { - QSize size; - int refreshRate; - ModeFlags flags; - int id; - - inline bool operator==(const Mode &other) const; - }; - enum class DpmsMode { On, Standby, @@ -218,8 +222,8 @@ public: QString description() const; Capabilities capabilities() const; QByteArray edid() const; - QVector modes() const; - void setModes(const QVector &modes); + QList> modes() const; + QSharedPointer currentMode() const; DpmsMode dpmsMode() const; virtual void setDpmsMode(DpmsMode mode); @@ -295,8 +299,7 @@ Q_SIGNALS: protected: void initialize(const QString &model, const QString &manufacturer, const QString &eisaId, const QString &serialNumber, - const QSize &physicalSize, - const QVector &modes, const QByteArray &edid); + const QSize &physicalSize, const QByteArray &edid); void setName(const QString &name) { @@ -312,7 +315,8 @@ protected: Q_UNUSED(enable); } - void setCurrentModeInternal(const QSize &size, int refreshRate); + void setModesInternal(const QList> &modes, const QSharedPointer ¤tMode); + void setCurrentModeInternal(const QSharedPointer ¤tMode); void setTransformInternal(Transform transform); void setDpmsModeInternal(DpmsMode dpmsMode); void setCapabilityInternal(Capability capability, bool on = true); @@ -334,17 +338,16 @@ private: QString m_model; QString m_serialNumber; QUuid m_uuid; - QSize m_modeSize; QSize m_physicalSize; QPoint m_position; qreal m_scale = 1; Capabilities m_capabilities; Transform m_transform = Transform::Normal; QByteArray m_edid; - QVector m_modes; + QList> m_modes; + QSharedPointer m_currentMode; DpmsMode m_dpmsMode = DpmsMode::On; SubPixel m_subPixel = SubPixel::Unknown; - int m_refreshRate = -1; bool m_isEnabled = true; bool m_internal = false; bool m_isPlaceholder = false; diff --git a/src/waylandoutputdevicev2.cpp b/src/waylandoutputdevicev2.cpp index 1a02f89354..8bf7d768d2 100644 --- a/src/waylandoutputdevicev2.cpp +++ b/src/waylandoutputdevicev2.cpp @@ -100,17 +100,17 @@ void WaylandOutputDevice::updateModes(Output *output) const auto modes = output->modes(); deviceModes.reserve(modes.size()); - for (const Output::Mode &mode : modes) { + for (const QSharedPointer &mode : modes) { OutputDeviceModeV2Interface::ModeFlags flags; - if (mode.flags & Output::ModeFlag::Current) { + if (output->currentMode() == mode) { flags |= OutputDeviceModeV2Interface::ModeFlag::Current; } - if (mode.flags & Output::ModeFlag::Preferred) { + if (mode->flags() & OutputMode::Flag::Preferred) { flags |= OutputDeviceModeV2Interface::ModeFlag::Preferred; } - OutputDeviceModeV2Interface *deviceMode = new OutputDeviceModeV2Interface(mode.size, mode.refreshRate, flags); + OutputDeviceModeV2Interface *deviceMode = new OutputDeviceModeV2Interface(mode->size(), mode->refreshRate(), flags); deviceModes << deviceMode; } m_outputDeviceV2->setModes(deviceModes);